-
-
Save svanellewee/5c0b0059f5e593e47f7753ffced7b724 to your computer and use it in GitHub Desktop.
| import sys | |
| import logging | |
| import struct | |
| logging.basicConfig(level=logging.DEBUG) | |
| logger =logging.getLogger(__name__) | |
| def get_int(data): | |
| return struct.unpack("<I", data)[0] | |
| DIR_HEADER_SIZE=12 | |
| def get_header(data_stream): | |
| retval = {} | |
| header = data_stream.read(DIR_HEADER_SIZE) | |
| retval.update(dict(wad_type = header[:4])) | |
| retval.update(dict(num_entries = get_int(header[4:8]))) | |
| retval.update(dict(directory_absolute_location = get_int(header[8:DIR_HEADER_SIZE]))) | |
| retval.update(dict(data_size = retval['directory_absolute_location'] - DIR_HEADER_SIZE)) | |
| return retval | |
| def get_data(data_stream, directory_location): | |
| return { "data": data_stream.read(directory_location)} | |
| def get_directory_entries(data_stream): | |
| while True: | |
| retval = {} | |
| item = data_stream.read(16) | |
| if len(item) != 16: | |
| raise StopIteration | |
| retval.update(dict(start = get_int(item[:4]))) | |
| retval.update(dict(size = get_int(item[4:8]))) | |
| retval.update(dict(name = item[8:16])) | |
| yield retval | |
| def build_directory(file_name): | |
| with open(file_name, 'r') as wad_file: | |
| header = get_header(wad_file) | |
| wad_file.seek(header['directory_absolute_location']) | |
| return [ i for i in get_directory_entries(wad_file)] | |
| directory = build_directory(sys.argv[1]) | |
| print len(directory) | |
| def extract_data(file_name, directory, lumps_of_interest=None): | |
| retval = {} | |
| with open(file_name, 'r') as wad_file: | |
| for lump in directory: | |
| if lumps_of_interest and lump['start'] not in lumps_of_interest: | |
| continue | |
| wad_file.seek(lump['start']) | |
| data = wad_file.read(lump['size']) | |
| #print lump, len(data) | |
| retval[lump['name'].strip('\0')] = data | |
| return retval | |
| E1M1_lumps = [ 67500, 68880, 75532, 94972, 96840, 105624, 106572, 113180, 115392, 116296 ] | |
| data = extract_data(sys.argv[1], directory, E1M1_lumps) | |
| for key, value in data.items(): | |
| print key, len(value) | |
| import io | |
| def get_vertexes(byte_stream): | |
| while True: | |
| byte_elem = byte_stream.read(4) | |
| if len(byte_elem) != 4: | |
| raise StopIteration | |
| yield struct.unpack("<hh", byte_elem) | |
| def get_linedefs(byte_stream): | |
| while True: | |
| byte_elem = byte_stream.read(14) | |
| if len(byte_elem) != 14: | |
| raise StopIteration | |
| retval = [] | |
| #yield [ ord(i) for i in byte_elem] # 16 bytes | |
| with io.BytesIO(byte_elem) as b: | |
| retval.append(struct.unpack("<hh", b.read(4))) | |
| # ignore the rest | |
| yield retval | |
| # a = struct.unpack("<hh", byte_elem[:4]) | |
| # a = struct.unpack("<hh", byte_elem[:4]) | |
| # a = struct.unpack("<hh", byte_elem[:4]) | |
| # a = struct.unpack("<hh", byte_elem[:4]) | |
| def get_dims(vertex_data): | |
| lower_left = None | |
| with io.BytesIO(vertex_data) as bio: | |
| low = min(v[0] for v in get_vertexes(bio)) | |
| bio.seek(0) | |
| left = min(v[1] for v in get_vertexes(bio)) | |
| bio.seek(0) | |
| high = max(v[0] for v in get_vertexes(bio)) | |
| bio.seek(0) | |
| right = max(v[1] for v in get_vertexes(bio)) | |
| lower_left = (low, left) | |
| upper_right = (high, right) | |
| return lower_left,upper_right | |
| lower_left, upper_right = get_dims(data['VERTEXES']) | |
| import svgwrite | |
| dwg = svgwrite.Drawing('test.svg', size = (abs(upper_right[0]), abs(upper_right[1]))) | |
| verts = [] | |
| with io.BytesIO(data['VERTEXES']) as bio: | |
| for v in get_vertexes(bio): | |
| x, y = (v[0] - lower_left[0])/10.0, (v[1] - lower_left[1])/10.0 | |
| verts.append((x,y)) | |
| dwg.add(svgwrite.shapes.Rect((x,y),size=(0.5,0.5), stroke='#333', stroke_width=3)) | |
| print len(verts),'LENG!' | |
| count = 0 | |
| with io.BytesIO(data['LINEDEFS']) as bio: | |
| for v in get_linedefs(bio): | |
| count += 1 | |
| a,b = v[0] | |
| print v, verts[a], verts[b] | |
| dwg.add(dwg.line(verts[a],verts[b],stroke='#333', stroke_width=1)) | |
| print count | |
| dwg.save() | |
| # some node fun. | |
| with io.BytesIO(data['NODES']) as nodedata: | |
| idx = 0 | |
| while True: | |
| dat = nodedata.read(8) | |
| if not dat: | |
| break | |
| print idx,struct.unpack("<hhhh", dat) | |
| idx +=1 | |
| nodedata.read(16) | |
| nodedata.read(4) |
| import sys | |
| import logging | |
| import struct | |
| logging.basicConfig(level=logging.DEBUG) | |
| logger =logging.getLogger(__name__) | |
| # def getbytes(data): | |
| # return struct.unpack('<I', data)[0] | |
| DIR_HEADER_SIZE=12 | |
| def get_directory(file_stream): | |
| ''' | |
| 0x00-0x03 string "PWAD" or "IWAD", defines whether the WAD is a PWAD or an IWAD | |
| 0x04-0x07 An integer specifying the number of entries in the directory | |
| 0x08-0x0b An integer holding a pointer to the location of the directory | |
| ''' | |
| retval = {} | |
| directory_raw = file_stream.read(DIR_HEADER_SIZE) | |
| retval.update({"wad_type": directory_raw[:4]}) | |
| retval.update({"num_entries": getbytes(directory_raw[4:8])[0]}) | |
| retval.update({"location": getbytes(directory_raw[8:12])[0]}) | |
| data_size = retval['location'] - DIR_HEADER_SIZE | |
| retval.update({'data': file_stream.read(data_size)}) | |
| return retval | |
| def get_lump(file_stream): | |
| lump = file_stream.read(16) | |
| if len(lump) != 16: | |
| return None | |
| retval = {} | |
| retval.update({"start": getbytes(lump[0:4])[0] - DIR_HEADER_SIZE}) | |
| retval.update({"size": getbytes(lump[4:8])[0]}) | |
| name = lump[8:16] | |
| retval.update({"name": name}) | |
| return retval | |
| def getbytes(data): | |
| return struct.unpack("<I", data) | |
| with open(sys.argv[1],'rb') as wadfile: | |
| directory_data = get_directory(wadfile) | |
| print directory_data['wad_type'], directory_data['location'], directory_data['num_entries'], len(directory_data['data']) | |
| while True: | |
| lump = get_lump(wadfile) | |
| if not lump: | |
| break | |
| data = directory_data['data'][lump['start']:lump['start']+lump['size']] | |
| print lump, len(data) | |
| if lump['name'] == 'VERTEXES': | |
| print struct.unpack("<hh", data[0:4]) | |
| print struct.unpack("<hh", data[4:8]) | |
| # print struct.unpack("<hh", data[0:4]) | |
| # print struct.unpack("<hh", data[0:4]) | |
| # lump_start = getbytes(data[0:4]) | |
| # lump_size = getbytes(data[4:8]) | |
| # lump_name = data[8:16] | |
(incomplete)
So it looks like WAD is a bit arse backwards, perhaps I'm wrong ?
The layout seems to be :
- header
- body
- index (dictionary)
Though my get_lump code is the thing that actually get's the index entries so that we can get the right stuff inside the body(ie the previous element)
I guess sqlite wasn't invented yet.
get_linedefs gets linedef packets of 14 (doom version) and only uses the first 4 bytes (start vertex index -end vertex index)
Code then ignores the rest for now
From http://zdoom.org/wiki/Linedef... read it as follows : 0-1 means byte 0 AND byte 1, 2-3 means byte 2 AND byte 3 etc.
Bytes Data type Description
0-1 Unsigned short Beginning vertex
2-3 Unsigned short Ending vertex
4-5 Unsigned short Flags
6-7 Unsigned short Line type
8-9 Unsigned short Sector tag
10-11 Unsigned short Right sidedef - 0xFFFF means there is no sidedef
12-13 Unsigned short Left sidedef - 0xFFFF means there is no sidedef

Rewrite of https://gist.github.com/jasonsperske/42284303cf6a7ef19dc3
and using http://zdoom.org/wiki/WAD as spec...
(just because I'm stupid and need things spelt out)