Another night of .obj failure

This commit is contained in:
2018-03-21 05:08:24 +00:00
parent 4db78f52fa
commit c4598590c2
4 changed files with 254 additions and 142 deletions

View File

@@ -19,7 +19,6 @@ module Obj
def self.parse(data)
hdr = new(*data[0..SIZE - 1].unpack("V*"))
pp hdr
hdr.validate!(data.bytes.size)
hdr
end
@@ -82,8 +81,6 @@ module Obj
DirEntry.parse(rel_data.byteslice(rel_offset, DirEntry::SIZE))
end
pp entries
new(entries)
end
@@ -94,38 +91,58 @@ module Obj
# Convert the directory into an Array of bytes. Until we work out how to
# parse sprites, anyway...
def realize(rel_data)
entries.map { |entry| rel_data[entry.sprite_range] }
entries.map { |entry| Sprite.parse(rel_data[entry.sprite_range]) }
end
end
=begin
SpriteHeader = Struct.new(
:unknown0, # Possibly magic data? It's the same for every sprite in jungtil.obj
:maybe_dimension, # Low nibble comes to 63 in jungtil.obj which would work for a 64x64 tile
:size, # Number of bytes of pixel data following this header
) do
SIZE = 4*6 # Seems to be, anyway. Based on
class SpriteHeader
SIZE = 24 # Seems to be, anyway. Based on the size here vs. the size in the dir
attr_reader(
:unknown0, # Possibly magic data? It's the same for every sprite in jungtil.obj
:width, # Low nibble comes to 63 in jungtil.obj which would work for a 64x64 tile
:height,
:unknown8,
:size, # Number of bytes of pixel data following this header
:unknown16,
:unknown20,
)
def self.parse(rel_data)
new(*sprite_data[0..SIZE-1]).unpack("V*")
new(*rel_data[0...SIZE].unpack("VvvVVVV"))
end
def initialize(*args)
@unknown0,
@width,
@height,
@unknown8,
@size,
@unknown16,
@unknown20 = *args
end
def pixel_range
SIZE...size # maybe,anyway
SIZE...(SIZE+size)
end
end
Sprite = Struct.new(
:header, :data
) do
class Sprite
attr_reader :header, :data, :raw
def self.parse(rel_data)
hdr = SpriteHeader.parse(rel_data)
sprite_pixels = rel_data[hdr.pixel_range]
Sprite.new(hdr, sprite_pixels)
new(hdr, sprite_pixels, rel_data)
end
def initialize(header, data, raw = nil)
@header = header
@data = data
@raw = raw
end
end
=end
class Parsed
attr_reader :header
@@ -210,10 +227,11 @@ end
def dump(filename, spriteno = -1)
obj = load_obj(filename)
# pp obj
if spriteno == -1
puts "Dumping all sprites for #{filename}"
obj.sprites.each { |sprite| display(sprite, header: true) }
obj.sprites.each { |sprite| display(sprite.raw, 2, header: true) }
else
puts "Dumping sprite #{spriteno} for #{filename}"
display(obj.sprites[spriteno])
@@ -227,37 +245,61 @@ end
# * DEFLATE / ZLIB
# * LZO
# * LZOP
# * RLE (maybe?)
#
# Maybe try:
# * RLE8: https://www.fileformat.info/format/bmp/corion-rle8.htm
def decompress(filename)
puts "\nAttempting decompression of #{filename}..."
require 'zlib'
puts "\nAttempting RLE decompression of #{filename}..."
obj = load_obj(filename)
obj.sprites.each_with_index do |sprite, i|
print "Sprite %02d..."%i
# Step through the start of each sprite so we aren't stopped by a hypothetical header
(0...64).each do |offset|
block = sprite.byteslice(offset, sprite.size-offset)
decompressed = []
data = sprite.data.bytes
hdr = sprite.header
begin
inflater = Zlib::Inflate.new(-32)
decompressed = ""
decompressed << inflater.inflate(block)
raise "0 bytes" if decompressed.size == 0
(0...hdr.height).each do |i|
# npackets = data.shift(1)[0] # ignore the packet byte
decompressed_line = []
puts "succeeded! sprite=#{i} offset=#{offset} decompressed_size=#{decompressed.size}"
puts "data:"
puts decompressed.inspect
exit 0
rescue => err
puts "failed: #{err}"
count = 0
loop do
cmd = data.shift(1)[0]
if cmd == 0 # end of stream
print "Done! #{data.size} bytes left. "
break
elsif cmd == nil
print "Ran out of data! "
break
elsif cmd > 128 # "negative" bytes say "copy abs(X) bytes unmodified from input to output"
decompressed_line.concat(data.shift(cmd-128))
else # "positive" bytes say "repeat the next byte X times"
decompressed_line.concat(data.shift(1)*cmd)
end
if decompressed_line.size == hdr.width
print "Done line! "
break
end
# if npackets > 0 && count == npackets
# print "Done packets! "
# break
# end
count+=1
end
raise "Bad length for line #{i}! #{decompressed_line.size} (Expected #{hdr.width})" if decompressed_line.size != hdr.width
decompressed << decompressed_line
end
#puts "failed"
puts "Decompressed: #{decompressed.flatten.size} bytes. Sprite pixels: #{hdr.width*hdr.height}"
#display(decompressed.map(&:chr).join(""))
end
end
@@ -277,7 +319,29 @@ def compare(filenames)
end
end
def sprites(filename)
obj = load_obj(filename)
puts filename + ":"
puts "\ti X Y Px bytes bits/px"
obj.sprites.each_with_index do |spr, i|
hdr = spr.header
px = hdr.width * hdr.height
puts "\t%02d: %03d %03d %04d %04d %.2f"%[
i,
hdr.width,
hdr.height,
px,
hdr.size,
(hdr.size*8) / px.to_f
]
end
end
case command = ARGV.shift
when "sprites" then
ARGV.each { |filename| sprites(filename) }
when "dump" then
ARGV.each { |filename| dump(filename) }
when "compare" then