ok. here for the first “dirty” pieces of code.
they are quite a mess but i aimed for functionality so far.
this code can convert most (no billboards, no curved surfaces) geometry including most textures (they are assumed to be .jpg files) into an egg file which can be loaded by panda directly.
so far there are no nodes, no hiarchy no BSP-calculations and no potential visibility stuff in there. just getting the geometry with textures. i’ll try to add more features. next would the loading of lightmaps.

so here’s the code, in case my train crashes tomorrow 
#python based reader for quake3 BSP files according to http://www.mralligator.com/q3/
#written by Thomas Egenhofer, released under BSD license.
#if you have any questions contact me: antitron@web.de
import struct
infile = open('/media/ext-hdd/Modellstuff/test/bsptests/maps/q3dm17.bsp',"rb")
outfile = open('./outfile.egg',"w")
outfile.write("<CoordinateSystem> { Z-Up } \n")
outfile.write("<Comment> { } \n")
#start reading the mapfile.. first comes the header. it contains magic number, version number
#and some information where to find what other data.
#that information is stored in 17 "Lumps". each containing different data.
magic = infile.read(4)
versionnumber = struct.unpack("<i" , infile.read(4))[0]
print "magic number:", magic
print "version number" , hex(versionnumber)
#for the entities lump in the bsp file.[ offset from file beginning, length of the data]
def readLumpEntry():
lumpEntry= [ struct.unpack("<i", infile.read(4))[0] ,
struct.unpack("<i", infile.read(4))[0] , ]
print lumpEntry
return lumpEntry
print "entities lump",
Entities = readLumpEntry() ;print "Textures lump",
Textures = readLumpEntry() ;print "Planes lump",
Planes = readLumpEntry() ;print "Nodes lump",
Nodes = readLumpEntry() ;print "Leafs lump",
Leafs = readLumpEntry() ;print "LeafFaces lump",
Leaffaces = readLumpEntry() ;print "LeafBrushes lump",
Leafbrushes = readLumpEntry() ;print "Models lump",
Models = readLumpEntry() ;print "Brushes lump",
Brushes = readLumpEntry() ;print "Brushsizes lump",
Brushsides = readLumpEntry() ;print "Vertices lump",
Vertices = readLumpEntry() ;print "MeshVerts lump",
Meshverts = readLumpEntry() ;print "Effects lump",
Effects = readLumpEntry() ;print "Faces lump",
Faces = readLumpEntry() ;print "Lightmaps lump",
Lightmaps = readLumpEntry() ;print "Lightvols lump",
Lightvols = readLumpEntry() ;print "Visdata lump",
Visdata = readLumpEntry()
print " END OF HEADER "
print
textures = []
####handling textures
def readTexture(offset):
infile.seek(offset)
texturename = infile.read(64).rstrip("\0")
#global textures
textures.append(texturename)
sourceFlags = struct.unpack("<i", infile.read(4))[0]
contentFlags= struct.unpack("<i", infile.read(4))[0]
#print
#print "texturename:" , texturename
#print "sourceFlags:", hex(sourceFlags) , "contentFlags:",hex(contentFlags)
def readTextures(offset,length):
numtextures = length/(64+4+4) #thats 64chars,4byte int, 4 byte int
print "Number of Textures",numtextures
for i in range(0,numtextures):
readTexture(offset+ i*(64+4+4) )
readTextures(Textures[0],Textures[1])
print "END OF TEXTURES"
###### end of texture handling
for i in textures:
outfile.write("<Texture> tex"+str(textures.index(i))+" { \n\t./"+i+".jpg \n\t<Scalar> uv-name { Diffuse } \n}" )
###handling meshvertices ### //nasty offsets values in the vertex-list later on.. i still dont get what it's good for..
meshVertsList=[]
def readMeshverts(offset,length):
infile.seek(offset)
numMeshverts = length / 4
print
print "number of meshVertices:", numMeshverts
for i in range(0,numMeshverts):
meshVertsList.append(struct.unpack("<i", infile.read(4))[0])
readMeshverts(Meshverts[0],Meshverts[1])
print meshVertsList
#### handling vertices YAY!.. we def need those
def readVertex(offset):
infile.seek(offset)
vertexPos = [ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
vertexUVDif = [ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
vertexUVLight=[ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
vertexNormal =[ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
vertexRGBA = [ struct.unpack("<B", infile.read(1))[0],
struct.unpack("<B", infile.read(1))[0],
struct.unpack("<B", infile.read(1))[0],
struct.unpack("<B", infile.read(1))[0] ]
#print "vertex Pos:",vertexPos
#print "vertex UV Diffusive:",vertexUVDif
#print "vertex UV Lightmap:",vertexUVLight
#print "vertex normal:", vertexNormal
#print "vertex color:",vertexRGBA
####writing to egg file:
outfile.write("\t\t\t"+repr(vertexPos[0])+ " " +repr(vertexPos[1]) +" "+repr(vertexPos[2]) +"\n" )
outfile.write("\t\t\t <Normal> { " +repr(vertexNormal[0])+ " " +repr(vertexNormal[1]) +" "+repr(vertexNormal[2]) +"}\n" )
outfile.write("\t\t\t <RGBA> { " +repr(vertexRGBA[0]/255.)+ " " +repr(vertexRGBA[1]/255.) +" "+repr(vertexRGBA[2]/255.)+ " " +repr(vertexRGBA[3]/255.) +" }\n" )
outfile.write("\t\t\t <UV> Diffuse { " +repr(vertexUVDif[0])+ " " +repr(1-vertexUVDif[1])+" }\n" )
outfile.write("\t\t\t <UV> Lightmap { " +repr(vertexUVLight[0])+ " " +repr(vertexUVLight[1])+" }\n" )
outfile.write("\t\t\t}\n")
def readVertices(offset , length):
outfile.write("<Group>{\n")
outfile.write("\t<VertexPool> BSPmap {\n")
numvertices = length / ( 3*4 + 2*4 + 2*4 + 3*4 +4*1)
print
print "number of numvertices:", numvertices
for i in range(0,numvertices):
#print
#print "vertexNr:" ,i
outfile.write("\t\t<Vertex> %i { \n"%i)
readVertex(offset+ i* ( 3*4 + 2*4 + 2*4 + 3*4 +4*1) )
outfile.write("\t\t}\n")
readVertices(Vertices[0],Vertices[1])
print "END OF VERTEXDATA"
#### end of handling vertices #####
#### handling of faces #####
def readFace(offset):
infile.seek(offset)
texture = struct.unpack("<i", infile.read(4))[0]
effect = struct.unpack("<i", infile.read(4))[0]
facetype = struct.unpack("<i", infile.read(4))[0]
vertex = struct.unpack("<i", infile.read(4))[0]
nVertices = struct.unpack("<i", infile.read(4))[0]
meshVertex = struct.unpack("<i", infile.read(4))[0]
nMeshVerts = struct.unpack("<i", infile.read(4))[0]
lightmapIndex = struct.unpack("<i", infile.read(4))[0]
lightmapStart =[ struct.unpack("<i", infile.read(4))[0],
struct.unpack("<i", infile.read(4))[0] ]
lightmapSize =[ struct.unpack("<i", infile.read(4))[0],
struct.unpack("<i", infile.read(4))[0] ]
lightmapOrigin =[ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
lightmapVecs =[ [struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ],
[struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ] ]
normal =[ struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0],
struct.unpack("<f", infile.read(4))[0] ]
patchSize =[ struct.unpack("<i", infile.read(4))[0],
struct.unpack("<i", infile.read(4))[0] ]
"""
print
print "texture index:", texture
print "effect index:", effect
print "face type:", facetype
print "vertex index:", vertex
print "number of vertices:",nVertices
print "mesh vertex:", meshVertex
print "number of mesh vertices:", nMeshVerts
print "lightmap index:", lightmapIndex
print "lightmap Start:", lightmapStart
print "lightmap Size:", lightmapSize
print "lightmap Origin:", lightmapOrigin
print "lightmap Vectors:", lightmapVecs
print "face normal:", normal
print "patch size:", patchSize
"""
"""
if facetype == 1 :
outfile.write("\t\t<Polygon> {\n")
outfile.write("\t\t\t<VertexRef> { ")
for j in range(0,nVertices):
outfile.write(str(vertex+nVertices-j-1)+" ")
outfile.write("<Ref> { BSPmap } } \n")
outfile.write("<TRef> { tex"+str(texture)+" }\n")
outfile.write("\t\t}\n")
"""
if facetype == 3 or facetype==1:
for n in range(0,nMeshVerts/3):
outfile.write("\t\t<Polygon> {\n")
outfile.write("\t\t\t<VertexRef> { ")
for j in range(0,3):
outfile.write(str(vertex+ meshVertsList[2+meshVertex+3*n-j] )+" ")
outfile.write("<Ref> { BSPmap } } \n")
outfile.write("<TRef> { tex"+str(texture)+" }\n")
outfile.write("\t\t}\n")
print facetype,vertex,nVertices,meshVertex,nMeshVerts
def readFaces(offset , length):
numfaces = length / (12*4 + 12*4+2*4)
print
print "number of numFaces:", numfaces
for i in range(0,numfaces):
#print
#print "faceNr:" ,i
readFace(offset+ i* (12*4 + 12*4+2*4) )
readFaces(Faces[0],Faces[1])
outfile.write("}")
outfile.close()
print "END OF FACEDATA"
#### end of handling faces ####
#print textures