#!BPY

""" 
Name: 'BSP'
Blender: 233
Group: 'Import'
Tip: 'Import Quake 3 Levels'
"""


######################################################
# BSP Importer
# By:  Bob Holcomb
# Date: 12 May 04
# Ver: 0.1
######################################################
# This script imports a Quake 3 BSP file and the materials
#  into blender for editing.  Hopefully
# this will make it into a future version as an import
# feature of the menu.  
######################################################

######################################################
# Importing modules
######################################################

import Blender
from Blender import NMesh, Scene, Object, Material
from Blender.BGL import *
from Blender.Draw import *
from Blender.Window import *
from Blender.Image import *
from Blender.Material import *

import sys, struct, string, types
from types import *

import os
from os import path


def asciiz (s):
  n = 0
  while (ord(s[n]) != 0):
    n = n + 1
  return s[0:n]


######################################################
# Constants
######################################################

Q3_BSP_magic_number    = "IBSP"
Q3_BSP_version    = 0x2E

NUM_LUMPS=17
                            
ENTITY_LUMP=0     #    = 0x00; // Entities : Game-related object descriptions.  
TEXTURE_LUMP=1    #    = 0x01; // Textures : Surface descriptions.  
PLANE_LUMP=2    #    = 0x02; // Planes : Planes used by map geometry.  
NODE_LUMP=3        #    = 0x03; // Nodes : BSP tree nodes.  
LEAF_LUMP=4        #    = 0x04; // Leafs : BSP tree leaves.  
LEAF_FACE_LUMP=5 #    = 0x05; // LeafFaces : Lists of face indices, one list per leaf.  
LEAF_BRUSH_LUMP=6 #    = 0x06; // LeafBrushes  Lists of brush indices, one list per leaf.  
MODEL_LUMP=7    #    = 0x07; // Models  Descriptions of rigid world geometry in map.  
BRUSH_LUMP=8    #    = 0x08; // Brushes  Convex polyhedra used to describe solid space.  
BRUSH_SIDE_LUMP=9 #    = 0x09; // Brushsides  Brush surfaces.  
VERTEX_LUMP=10    #    = 0x0A; // Vertexes  Vertices used to describe faces.  
MESH_VERT_LUMP=11 #    = 0x0B; // MeshVerts  Lists of offsets, one list per mesh.  
SHADER_LUMP=12    #    = 0x0C; // Effects  List of special map effects.  
FACE_LUMP=13    #    = 0x0D; // Faces  Surface geometry.  
LIGHT_MAP_LUMP=14 #    = 0x0E; // LightMaps  Packed lightmap data.  
LIGHT_VOL_LUMP=15 #    = 0x0F; // LightVols  Local illumination data.  
VIS_DATA_LUMP=16#    = 0x10; // Visdata  Cluster-cluster visibility data.


######################################################
# Data Structures
######################################################

class c_lump:
	offset=0
	length=0
	binary_format="<2i"
	
	def __init__(self):
		self.offset=0
		self.length=0
	
	def read(self,file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.offset=data[0]
		self.length=data[1]
		
	def dump(self):
		print "Lump Dump"  #sounds funny
		print "Offset: ", self.offset
		print "Length: ", self.length
        
    
class c_header:
	magic_number=""
	version=0
	lumps=[]
	binary_format="<4si"
	
	def __init__(self):
		self.magic_number=""
		self.vesion=0
		self.lumps=[]
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.magic_number=data[0]
		self.version=data[1]
		for lump_counter in range (0, NUM_LUMPS):
			self.lumps.append(c_lump())
			self.lumps[lump_counter].read(file)
	
	def dump(self):
		print "Header dump"
		print "Magic Number: ", self.magic_number
		print "Version: ", self.version
		print "Lumps: "
		for lump_counter in range (0, NUM_LUMPS):
			print "Lump ", lump_counter, " : ", self.lumps[lump_counter].dump() 
        
class c_entity:
	size=0
	buffer=""
	binary_format=""  #the buffer varies in size don't read it in right away
	
	def __init__(self):
		self.size=0
		self.buffer=""
	
	def read(self, file):
		self.binary_format="<"+str(self.size)+"s"
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.buffer=data[0]
	
	def dump(self):
		print "Entity Dump"
		print "Size: ", self.size
		print "Buffer: ", self.buffer
        

class c_texture:
	name=""
	flags=0
	contents=0
	binary_format="<64s2i"
	
	def __init__(self):
		self.name=""
		self.flags=0
		self.contents=0
	
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.name=data[0]
		self.flags=data[1]
		self.contents=data[2]
	
	def dump(self):
		print "Texture Dump"
		print "Name: ", self.name
		print "Flags: ", self.flags
		print "Contents: ", self.contents

class c_plane:
	normal=[]
	distance=0.0
	binary_format="<4f"
	
	def __init__(self):
		self.normal=[0.0]*3
		self.distance=0.0
	
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.normal=(data[0],data[1], data[2])
		self.distance=data[3]
	
	def dump(self):
		print "Plane Dump"
		print "Normal: ", self.normal
		print "Distance: ", self.distance
        
class c_node:
	plane_index=0
	children_index=[]
	min_box=[]
	max_box=[]
	binary_format="<9i"
	
	def __init__(self):
		self.plane_index=0
		self.children_index=[0]*2
		self.min_box=[0]*3
		self.max_box=[0]*3
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.plane_index=data[0]
		self.children_index=(data[1], data[2])
		self.min_box=(data[3], data[4], data[5])
		self.max_box=(data[6], data[7], data[8])
	
	def dump(self):
		print "Node Dump"
		print "Plane Index: ", self.plane_index
		print "Children Index: ", self.children_index
		print "Min box: ", self.min_box
		print "Max box: ", self.max_box

class c_leaf:
	cluster=0
	area=0
	min_box=[]
	max_box=[]
	leaf_face=0
	num_leaf_faces=0
	leaf_brush=0
	num_leaf_brushes=0
	binary_format="<12i"
	
	def __init__(self):
		self.cluster=0
		self.area=0
		self.min_box=[0]*3
		self.max_box=[0]*3
		self.leaf_face=0
		self.num_leaf_faces=0
		self.leaf_brush=0
		self.num_leaf_brushes=0
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.cluster=data[0]
		self.area=data[1]
		self.min_box=(data[2], data[3], data[4])
		self.max_box=(data[5], data[6], data[7])
		self.leaf_face=data[8]
		self.num_leaf_faces=data[9]
		self.leaf_brush=data[10]
		self.num_leaf_brushes=data[11]
	
	def dump(self):
		print "Leaf Dump"
		print "Cluster: ", self.cluster
		print "Area: ", self.area
		print "Min box: ", self.min_box
		print "Max box: ", self.max_box
		print "Leaf Face: ", self.leaf_face
		print "Number of Leaf Faces: ", self.num_leaf_faces
		print "Leaf Brush: ", self.leaf_brush
		print "Number of Leaf Brushes: ", self.num_leaf_brushes

class c_leaf_face:
	face_index=0
	binary_format="<i"
	
	def __init__(self):
		self.face_index=0
		
	def read(self,file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.face_index=data[0]
		
	def dump(self):
		print "Leaf Face Dump"
		print "Face Index: ", self.face_index
	
class c_leaf_brush:
	brush_index=0
	binary_format="<i"
	
	def __init__(self):
		self.brush_index=0;

	def read(self,file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.brush_index=data[0]
		
	def dump(self):
		print "Leaf Brush Dump"
		print "Brush Index: ", self.brush_index
        

class c_model:
	min_box=[]
	max_box=[]
	face_index=0
	num_faces=0
	brush_index=0
	num_brushes=0
	binary_format="<6f4i"
	
	def __init__(self):
		self.min_box=[0.0]*3
		self.max_box=[0.0]*3
		self.face_index=0
		self.num_faces=0
		self.brush_index=0
		self.num_brushes=0
		
	def read(self,file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.min_box=(data[0], data[1], data[2])
		self.max_box=(data[3], data[4], data[5])
		self.face_index=data[6]
		self.num_faces=data[7]
		self.brush_index=data[8]
		self.num_brushes=data[9]
		
	def dump(self):
		print "Model Dump"
		print "Min box: ", self.min_box
		print "Max box: ", self.max_box
		print "Face Index: ", self.face_index
		print "Number of Faces: ", self.num_faces
		print "Brush Index: ", self.brush_index
		print "Number of Brushes: ", self.num_brushes
        
class c_brush:
	brush_side=0
	num_brush_sides=0
	texture_index=0
	binary_format="<3i"
	
	def __init__(self):
		self.brush_side=0
		self.num_brush_sides=0
		self.texture_index=0
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.brush_side=data[0]
		self.num_brush_sides=data[1]
		self.texture_index=data[2]
	
	def dump(self):
		print "Brush Dump"
		print "Brush Side: ", self.brush_side
		print "Number of Brush Sides: ", self.num_brush_sides
		print "Texture Index: ", self.texture_index

class c_brush_side:
	plane_index=0
	texture_index=0
	binary_format="<2i"
	
	def __init__(self):
		self.plane_index=0
		self.texture_index=0
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.plane_index=data[0]
		self.texture_index=data[1]
	
	def dump(self):
		print "Brush Side Dump"
		print "Plane Index: ", self.plane_index
		print "Texture Index: ", self.texture_index

class c_vertex:
	position=[]
	texture_coords=[]
	lightmap_coords=[]
	normal=[]
	color=[]
	binary_format="<10f4B"
	
	def __init__(self):
		self.position=[0.0]*3
		self.texture_coods=[0.0]*2
		self.lightmap_coords=[0.0]*2
		self.normal=[0.0]*3
		self.color=[0]*4
	
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.position=(data[0], data[1], data[2])
		self.texture_coords=(data[3],data[4])
		self.lightmap_coords=(data[5], data[6])
		self.normal=(data[7], data[8], data[9])
		self.color=(data[10], data[11], data[12],data[13])
	
	def dump(self):
		print "Vertex Dump"
		print "Position: ", self.position
		print "Texture Coordinates: ", self.texture_coords
		print "Lightmap coordinates: ", self.lightmap_coords
		print "Normal: ", self.normal
		print "Color: ", self.color

class c_mesh_vert:
	mesh_vert_index=0
	binary_format="<i"
	
	def __init__(self):
		self.mesh_vert_index=0
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.mesh_vert_index=data[0]

	def dump(self):
		print "Mesh Vertex Dump"
		print "Mesh Vertex Index: ", self.mesh_vert_index
        
class c_shader:
	name=[]
	brush=0
	unknown=0
	binary_format="<64s2i"
	
	def __init__(self):
		self.name=""
		self.brush=0
		self.unknown=0

	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.name=data[0]
		self.brush=data[1]
		self.unknown=data[2]
	
	def dump(self):
		print "Shader Dump"
		print "Name: ", self.name
		print "Brush: ", self.brush
		print "Unknown: ", self.unknown
		
class c_face: 
	texture_index=0
	shader_index=0
	type=0
	vert_index=0
	num_verts=0
	mesh_vert_index=0
	num_mesh_verts=0
	lightmap_index=0
	lightmap_corner=[]
	lightmap_size=[]
	lightmap_origin=[]
	lightmap_vecs=[]
	normal=[]
	patch_size=[]
	binary_format="<12i12f2i"
	
	def __init__(self):
		self.texture_index=0
		self.shader_index=0
		self.type=0
		self.vert_index=0
		self.num_verts=0
		self.mesh_vert_index=0
		self.num_mesh_verts=0
		self.lightmap_index=0
		self.lightmap_corner=[0]*2
		self.lightmap_size=[0]*2
		self.lightmap_origin=[0.0]*3
		#may have this backwards its float lMapBitsets [2][3]
		self.lightmap_vecs=[None]*3
		for lm in self.lightmap_vecs:
			lm=[0.0]*2
		self.normal=[0.0]*3
		self.patch_size=[0]*2
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.texture_index=data[0]
		self.shader_index=data[1]
		self.type=data[2]
		self.vert_index=data[3]
		self.num_verts=data[4]
		self.mesh_vert_index=data[5]
		self.num_mesh_verts=data[6]
		self.lightmap_index=data[7]
		self.lightmap_corner=(data[8],data[9])
		self.lightmap_size=(data[10],data[11])
		self.lightmap_origin=(data[12],data[13],data[14])
		self.lightmap_vecs=((data[15],data[16]),(data[17],data[18]),(data[19],data[20]))
		self.normal=(data[21],data[22],data[23])
		self.patch_size=(data[24],data[25])
		
	def dump(self):
		print "Face Dump"
		print "Texture Index: ", self.texture_index
		print "Shader Index: ", self.shader_index
		print "Type: ", self.type
		print "Vert Index: ", self.vert_index
		print "Number of Verts: ", self.num_verts
		print "Mesh Vert Index: ", self.mesh_vert_index
		print "Number of Mesh Verts: ", self.num_mesh_verts
		print "Lightmap Index: ", self.lightmap_index
		print "Lightmap Corner: ", self.lightmap_corner
		print "Lightmap Size: ", self.lightmap_size
		print "Lightmap Origin: ", self.lightmap_origin
		print "Lightmap Vectors: ", self.lightmap_vecs
		print "Normal: ", self.normal
		print "Patch Size: ", self.patch_size

class c_light_map:
	map_data=[]
	binary_format="<49152B"
	
	def __init__(self):
		self.map_data=[0]*49152
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		for buffer_counter in range (0,49152):
			self.map_data[buffer_counter]=data[buffer_counter]
		
		
	def dump(self):
		print "Light map Dump"
		print "Light Map: ", self.map_data

class c_light_vol:
	ambient=[]
	dir_color=[]
	dir_type=[]
	binary_format="<8B"
	
	def __init__(self):
		self.ambient=[0]*3
		self.dir_color=[0]*3
		self.dir_type=[0]*2
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.ambient=(data[0],data[1],data[2])
		self.dir_color=(data[3],data[4],data[5])
		self.dir_type=(data[6],data[7])
		
	def dump(self):
		print "Light Volume Dump"
		print "Ambient: ", self.ambient
		print "Dir Color: ", self.dir_color
		print "Dir Type: ", self.dir_type
		
class c_vis_data:
	num_clusters=0
	bytes_per_cluster=0
	buffer=[]
	binary_format="<2i"  #the buffer is dynamic, load it seperatly
	
	def __init__(self):
		self.num_clusters=0
		self.bytes_per_cluster=0
		self.buffer=[]
		
	def read(self, file):
		temp_data=file.read(struct.calcsize(self.binary_format))
		data=struct.unpack(self.binary_format, temp_data)
		self.num_clusters=data[0]
		self.bytes_per_cluster=data[1]
		buffer_size=self.num_clusters*self.bytes_per_cluster
		self.buffer=[0]*buffer_size
		for buffer_counter in range (0,buffer_size):
			temp_data=file.read(struct.calcsize("<b"))
			data=struct.unpack("<b", temp_data)
			self.buffer[buffer_counter]=data[0]
		
	def dump(self):
		print "Visibility Data Dump"
		print "Number of Clusters: ", self.num_clusters
		print "Bytes Per Cluster: ", self.bytes_per_cluster
		print "Buffer: ", self.buffer

class c_map:
	header=c_header()
	entity=c_entity()
	num_textures=0
	textures=[]
	num_planes=0
	planes=[]
	num_nodes=0
	nodes=[]
	num_leaves=0
	leaves=[]
	num_leaf_faces=0
	leaf_faces=[]
	num_leaf_brushes=0
	leaf_brushes=[]
	num_models=0
	models=[]
	num_brushes=0
	brushes=[]
	num_brush_sides=0
	brush_sides=[]
	num_verts=0
	verts=[]
	num_mesh_verts=0
	mesh_verts=[]
	num_shaders=0
	shaders=[]
	num_faces=0
	faces=[]
	num_light_maps=0
	light_maps=[]
	num_light_volumes=0
	light_volumes=[]
	vis_data=c_vis_data()
    
	def __init__(self):
		self.header=c_header()
		self.entity=c_entity()
		self.num_textures=0
		self.textures=[]
		self.num_planes=0
		self.planes=[]
		self.num_nodes=0
		self.nodes=[]
		self.num_leaves=0
		self.leaves=[]
		self.num_leaf_faces=0
		self.leaf_faces=[]
		self.num_leaf_brushes=0
		self.leaf_brushes=[]
		self.num_models=0
		self.models=[]
		self.num_brushes=0
		self.brushes=[]
		self.num_brush_sides=0
		self.brush_sides=[]
		self.num_verts=0
		self.verts=[]
		self.num_mesh_verts=0
		self.mesh_verts=[]
		self.num_shaders=0
		self.shaders=[]
		self.num_faces=0
		self.faces=[]
		self.num_light_maps=0
		self.light_maps=[]
		self.num_light_volumes=0
		self.light_volumes=[]
		self.vis_data=c_vis_data()


#***********************************************
# Import Functions
#***********************************************
def read_header(map, file):
	#read in the header
	map.header.read(file)
	
	if ((map.header.magic_number==Q3_BSP_magic_number) and (map.header.version==Q3_BSP_version)):
		print "Magic Number and Version are correct"
		print "Magic Number: ",Q3_BSP_magic_number, " equal to file: ", map.header.magic_number
		print "Version: ", Q3_BSP_version, " equal to file: ", map.header.version
		return True
	else:
		print "Magic Number and Version are wrong"
		print "Magic Number: ",Q3_BSP_magic_number, " not equal to file: ", map.header.magic_number
		print "Version: ", Q3_BSP_version, "not equal to file: ", map.header.version
		return False
	#map.header.dump()
    
def read_entity(map, file):
	map.entity.size=map.header.lumps[ENTITY_LUMP].length
	file.seek(map.header.lumps[ENTITY_LUMP].offset,0)
	map.entity.read(file)
	#map.entity.dump()
	
def read_texture(map, file):
	map.num_textures=map.header.lumps[TEXTURE_LUMP].length/struct.calcsize(c_texture.binary_format)
	
	file.seek(map.header.lumps[TEXTURE_LUMP].offset,0)
	
	for texture_counter in range (0, map.num_textures):
		map.textures.append(c_texture())
		map.textures[texture_counter].read(file)
		#map.textures[texture_counter].dump()
        
def read_plane(map, file):
	map.num_planes=map.header.lumps[PLANE_LUMP].length/struct.calcsize(c_plane.binary_format)
	
	file.seek(map.header.lumps[PLANE_LUMP].offset,0)
	
	for plane_counter in range (0, map.num_planes):
		map.planes.append(c_plane())
		map.planes[plane_counter].read(file)
		#map.planes[plane_counter].dump()
		
def read_node(map, file):
	map.num_nodes=map.header.lumps[NODE_LUMP].length/struct.calcsize(c_node.binary_format)
	
	file.seek(map.header.lumps[NODE_LUMP].offset,0)
	
	for node_counter in range (0, map.num_nodes):
		map.nodes.append(c_node())
		map.nodes[node_counter].read(file)
		#map.nodes[node_counter].dump()
		
def read_leaf(map, file):
	map.num_leaves=map.header.lumps[LEAF_LUMP].length/struct.calcsize(c_leaf.binary_format)
	
	file.seek(map.header.lumps[LEAF_LUMP].offset,0)
	
	for leaf_counter in range (0, map.num_leaves):
		map.leaves.append(c_leaf())
		map.leaves[leaf_counter].read(file)
		#map.leaves[leaf_counter].dump()
		
def read_leaf_face(map, file):
	map.num_leaf_faces=map.header.lumps[LEAF_FACE_LUMP].length/struct.calcsize(c_leaf_face.binary_format)
	
	file.seek(map.header.lumps[LEAF_FACE_LUMP].offset,0)
	
	for leaf_face_counter in range (0, map.num_leaf_faces):
		map.leaf_faces.append(c_leaf_face())
		map.leaf_faces[leaf_face_counter].read(file)
		#map.leaf_faces[leaf_face_counter].dump()
		
def read_leaf_brush(map, file):
	map.num_leaf_brushes=map.header.lumps[LEAF_BRUSH_LUMP].length/struct.calcsize(c_leaf_brush.binary_format)
	
	file.seek(map.header.lumps[LEAF_BRUSH_LUMP].offset,0)
	
	for leaf_brush_counter in range (0, map.num_leaf_brushes):
		map.leaf_brushes.append(c_leaf_brush())
		map.leaf_brushes[leaf_brush_counter].read(file)
		#map.leaf_brushes[leaf_brush_counter].dump()
		
def read_model(map, file):
	map.num_models=map.header.lumps[MODEL_LUMP].length/struct.calcsize(c_model.binary_format)
	
	file.seek(map.header.lumps[MODEL_LUMP].offset,0)
	
	for model_counter in range (0, map.num_models):
		map.models.append(c_model())
		map.models[model_counter].read(file)
		map.models[model_counter].dump()
		
def read_brush(map, file):
	map.num_brushes=map.header.lumps[BRUSH_LUMP].length/struct.calcsize(c_brush.binary_format)
	
	file.seek(map.header.lumps[BRUSH_LUMP].offset,0)
	
	for brush_counter in range (0, map.num_brushes):
		map.brushes.append(c_brush())
		map.brushes[brush_counter].read(file)
		#map.brushes[brush_counter].dump()
		
def read_brush_side(map, file):
	map.num_brush_sides=map.header.lumps[BRUSH_SIDE_LUMP].length/struct.calcsize(c_brush_side.binary_format)
	
	file.seek(map.header.lumps[BRUSH_SIDE_LUMP].offset,0)
	
	for brush_side_counter in range (0, map.num_brush_sides):
		map.brush_sides.append(c_brush_side())
		map.brush_sides[brush_side_counter].read(file)
		#map.brush_sides[brush_side_counter].dump()
		
def read_vertex(map, file):
	map.num_verts=map.header.lumps[VERTEX_LUMP].length/struct.calcsize(c_vertex.binary_format)
	
	file.seek(map.header.lumps[VERTEX_LUMP].offset,0)
	
	for vert_counter in range (0, map.num_verts):
		map.verts.append(c_vertex())
		map.verts[vert_counter].read(file)
		#map.verts[vert_counter].dump()
		
def read_mesh_vert(map, file):
	map.num_mesh_verts=map.header.lumps[MESH_VERT_LUMP].length/struct.calcsize(c_mesh_vert.binary_format)
	
	file.seek(map.header.lumps[MESH_VERT_LUMP].offset,0)
	
	for mesh_vert_counter in range (0, map.num_mesh_verts):
		map.mesh_verts.append(c_mesh_vert())
		map.mesh_verts[mesh_vert_counter].read(file)
		#map.mesh_verts[mesh_vert_counter].dump()
		
def read_shader(map, file):
	map.num_shaders=map.header.lumps[SHADER_LUMP].length/struct.calcsize(c_shader.binary_format)
	
	file.seek(map.header.lumps[SHADER_LUMP].offset,0)
	
	for shader_counter in range (0, map.num_shaders):
		map.shaders.append(c_shader())
		map.shaders[shader_counter].read(file)
		#map.shaders[shader_counter].dump()
		
def read_face(map, file):
	map.num_faces=map.header.lumps[FACE_LUMP].length/struct.calcsize(c_face.binary_format)
	
	file.seek(map.header.lumps[FACE_LUMP].offset,0)
	
	for face_counter in range (0, map.num_faces):
		map.faces.append(c_face())
		map.faces[face_counter].read(file)
		#map.faces[face_counter].dump()
		
def read_light_map(map, file):
	map.num_light_maps=map.header.lumps[LIGHT_MAP_LUMP].length/struct.calcsize(c_light_map.binary_format)
	
	file.seek(map.header.lumps[LIGHT_MAP_LUMP].offset,0)
	
	for light_map_counter in range(0,map.num_light_maps):
		map.light_maps.append(c_light_map())
		map.light_maps[light_map_counter].read(file)
		#map.light_maps[light_map_counter].dump()
	
def read_light_vol(map, file):
	map.num_light_volumes=map.header.lumps[LIGHT_VOL_LUMP].length/struct.calcsize(c_light_vol.binary_format)
	
	file.seek(map.header.lumps[LIGHT_VOL_LUMP].offset, 0)
	
	for light_vol_counter in range(0,map.num_light_volumes):
		map.light_volumes.append(c_light_vol())
		map.light_volumes[light_vol_counter].read(file)
		#map.light_volumes[light_vol_counter].dump()
		
def read_vis_data(map, file):
	file.seek(map.header.lumps[VIS_DATA_LUMP].offset,0)
	map.vis_data.read(file)
	#map.vis_data.dump()

def read_map(map, file):
	read_entity(map, file)
	read_texture(map, file)
	read_plane(map, file)
	read_node(map, file)
	read_leaf(map, file)
	read_leaf_face(map, file)
	read_leaf_brush(map, file)
	read_model(map, file)
	read_brush(map, file)
	read_brush_side(map, file)
	read_vertex(map, file)
	read_mesh_vert(map, file)
	read_shader(map, file)
	read_face(map, file)
	read_light_vol(map, file)
	read_vis_data(map, file)
	read_light_map(map, file)

def load_textures(map):
	#need to set this in the gui
	base_path="/home/bob/blender/scripts/BSP/"
	
	#for each texture
	for tex in map.textures:
		#clean the path name (get rid of the blanks)
		clean_path=asciiz(tex.name)
		
		#get the texture name
		split_path=string.split(clean_path,"/")
		texture_name=split_path[len(split_path)-1]
		
		#create a texture object
		b_tex=Blender.Texture.New(texture_name)
		b_tex.setType("Image")
		
		#if there is a valid texture file, load it into the object load it
		if (os.path.isfile(base_path+clean_path+".tga")):
			mesh_image=Blender.Image.Load(base_path+clean_path+".tga")
			b_tex.setImage(mesh_image)
		
		#create a material object to attatch the texture to
		b_mat=Blender.Material.New(texture_name)
		b_mat.setTexture(0,b_tex)
			
def load_mesh(map):
	#get list of textures
	tex_list=Blender.Texture.Get()
	#create a new blender mesh
	level_mesh=Blender.NMesh.New("BSP_Level")

	#add the verticies to it
	for v in map.verts:
		temp_vert=Blender.NMesh.Vert(v.position[0],v.position[1],v.position[2])#may need to swap y and z
		temp_vert.uvco=(v.texture_coords[0],v.texture_coords[1])  #may need to 1-v for texture
		level_mesh.verts.append(temp_vert)
		
	#add the faces to it (with textures)
	for f in map.faces:
		if (f.type==1):  # if it's a regular polygon tri-fans
			first_vertex=f.vert_index
			for tri_counter in range(0,(f.num_verts-2)):
				#create face
				face=Blender.NMesh.Face()
				face.append(level_mesh.verts[first_vertex])
				face.append(level_mesh.verts[first_vertex+tri_counter+2])
				face.append(level_mesh.verts[first_vertex+tri_counter+1])
				
				#not working for some reason
				if (f.texture_index >0 and f.texture_index<(len(tex_list))):
					temp_tex=tex_list[f.texture_index].getImage()
					if (temp_tex!=None):
						face.image=temp_tex
				
				#add the face
				level_mesh.faces.append(face)
		
		elif (f.type==2): #bezier patch
			pass  #I don't know how to do this
			
		
		elif (f.type==3):  #mesh verts
			first_vertex=f.vert_index
			for tri_counter in range (0,(f.num_verts-2)):
				#create face
				face=Blender.NMesh.Face()
				
				#doesn't work right
				face.append(level_mesh.verts[first_vertex+tri_counter])
				face.append(level_mesh.verts[first_vertex+tri_counter+2])
				face.append(level_mesh.verts[first_vertex+tri_counter+1])
								
				#not working for some reason
				if (f.texture_index >0 and f.texture_index<(len(tex_list))):
					temp_tex=tex_list[f.texture_index].getImage()
					if (temp_tex!=None):
						face.image=temp_tex
				
				#add the face
				#level_mesh.faces.append(face)
		
		elif (f.type==4):  #billboard
			pass  #I haven't gotten this far yet
		else:
			print "Not a type 1..4 face, instead a type ", f.type, " face"

	#turn on vertex UV coordinates
	level_mesh.hasVertexUV(1)
	mesh_obj=Blender.NMesh.PutRaw(level_mesh,"BSP_Level",1)

def load_blender(map):
	#load textures
	load_textures(map)
	
	#load the level mesh
	load_mesh(map)
	
	#create blender meshes for each model
	for model in map.models:
		#load verts
		#load faces based on type
		pass
	
def load_bsp(filename):
	#open the file for reading
	file=open(filename,"rb")
	#create a map structure to put info into
	map_object=c_map()
	#read the header and check the information    
	if(read_header(map_object, file)):
		#here's the where the file is read and put into blender
		read_map(map_object, file)
	else:
		#oops, not a good file
		print "Not a valid Q3 BSP file: ", filename
	
	#close the file and back to blender
	file.close()
	
	load_blender(map_object)

#***********************************************
# MAIN
#***********************************************


def my_callback(filename):
	load_bsp(filename)

Blender.Window.FileSelector(my_callback, "Import Q3 Map")



        

