class Header attr_reader :kind, :num_faces, :zoom, :num_points, :unk1 def initialize(kind, num_faces, zoom, num_points, unk1) @kind = kind @num_faces = num_faces @zoom = zoom @num_points = num_points @unk1 = unk1 end def Header.read(f) buf = f.read(18) items = buf.unpack("vVeVV") Header.new(*items) end end class Point attr_reader :id, :x, :y, :z def initialize(id, x, y, z) @id = id @x = x @y = y @z = z end def Point.read(f) items = f.read(16).unpack("Veee") Point.new(*items) end end # each face stores a reference to the used texture. # this includes the name of the texture (eg mod_001) class Face attr_accessor :id, :kind def initialize @id = 0 @kind = 0 end def self.read(f) face = Face.new # read at 0x901e1 face.id = f.read(4).unpack('V').first # read at 0x901f4 and again at 0x88554 face.kind = f.read(2).unpack('v').first # read at 0x8d563. UNKNOWN. f.read 24 # read at 0xb948e. # is the same value for every face in a given module. buf0 = f.read 4 # read at 0xb949e. not evaluated. f.read 4 # read at 0xb94ae. # is the same value for every face in a given module. buf1 = f.read 4 # read at 0xb94be. buf2 = f.read 4 # read at 0xb94ce. buf3 = f.read 4 # read at 0xb94de. not evaluated. f.read 4 edi = buf3.unpack('V').first #puts " #{edi}" # ^^^ could this be the number of vertices that belong to this face? # read at 0xb950b. # this might be the the coordinates of the texture rectangle # that's to be used by this face. 8 bytes = two ints: # eg: x, y _ = f.read edi * 8 #p _.unpack('VV') # read real module/texture reference: # read at 0x14d9f string_length = f.read(4).unpack('V').first # read at 0x14dab. not evaluated. f.read 4 # read at 0x14dc7 tex_name = f.read string_length puts "using texture: #{tex_name}" # this might be the corners of the face, given as float vectors. _ = f.read(4 * 3 * edi) p _.unpack('e*') face end end f = File.open(ARGV.shift, 'rb') header = Header.read(f) puts "kind: #{header.kind}" puts "zoom: #{header.zoom}" puts "#faces: #{header.num_faces}" puts "#points: #{header.num_points}" puts "unk1: #{header.unk1}" points = [] faces = [] header.num_points.times do |i| points << Point.read(f) end # puts "point IDs:" # p points.map { |point| point.id }.sort puts "done reading vertices. file offset: #{ '0x%x' % f.tell }" header.num_faces.times do |i| puts "reading face #{i} at #{ '0x%x' % f.tell}" faces << Face.read(f) end puts "done reading faces. file offset: #{ '0x%x' % f.tell}" puts "reading module footer" # read at 0x902da f.read 4 # read at 0x902e8. num_faces? t = f.read(4).unpack('V').first unless t == header.num_faces raise "expected #{header.num_faces}, but got #{t}" end # read at 0x902f6. num_faces? t = f.read(4).unpack('V').first unless t == header.num_faces raise "expected #{header.num_faces}, but got #{t}" end 8.times do raise 'hit eof unexpectedly' if f.eof? # read at 0x9037f: each face's ID is read once. # maybe this puts the faces in some order? # note: # only the first four blocks seem to be read. f.read header.num_faces * 4 end puts "file offset: #{ '0x%x' % f.tell}" puts "at EOF? #{f.eof?}"