WHITELEAF:Kindle応援サイト

KindleでWEB小説を読もう! Narou.rb 公開中

Ruby で構造体もどき 続き

前回の続き

BinData と比較するためにコードを作成。

約1Mのモデルデータを読み込むコードです。BinData を使ったほうは2.5秒かかりました。自前の unpack ラッパーは約0.07秒。(PCスペックに左右されるので参考程度)

BinData は柔軟な記述ができる代わりに、いちいち数バイトずつ読み込んでるので死ぬほど遅いです。Ruby の場合(1.9.x限定かも)、ファイルを少しずつ読むと極端に速度が遅くなるという現象(ある程度改善されたようですが)があるので、最初に全てのデータを読み込んだほうが劇的に速度があがります。

さらに File.read する場合にファイルサイズを指定するとさらに読み込み速度が上がる(バイナリモード用?)ので、File.read(file_name, File.size(file_name)) とやったほうが良いです。

(追記)
StringIO を使って最初に全て読み込んでから BinData に食わせてみたところ、1.2秒までタイムが短縮しました。半分以下に。やっぱりファイルシークさせちゃダメですね。
でもやっぱりまだまだ遅いので、実用にはきびしい感じ(小さいファイルならまったく問題はありませんけど)

# BinData を使用した場合
require "bindata"

class PMD < BinData::Record
  class Header < BinData::Record
    endian :little
    string :magic, :length => 3
    float :version
    string :model_name, :length => 20
    string :comment, :length => 256
    uint32 :vert_count
  end

  class Vector < BinData::Record
    endian :little
    float :x
    float :y
    float :z
  end

  class Vertex < BinData::Record
    endian :little
    vector :pos
    vector :normal_vec
    float :u
    float :v
    array :bone_num, :type => :uint16, :initial_length => 2
    uint8 :bone_weight
    uint8 :edge_flag
  end

  endian :little
  header :header
  array :vertex, :type => :vertex, :initial_length => ->{ header.vert_count }
end

pmd = PMD.new
pmd.read(File.open("normal.pmd"))
puts pmd.header.magic
puts pmd.header.version
puts pmd.header.model_name.unpack("Z*")
puts pmd.header.comment.unpack("Z*")
puts pmd.header.vert_count
puts pmd.vertex[0]
class PMD
  # 〜略〜
  def test
    bin = BinStruct::Stream.new("normal.pmd")
    header = bin.read(Header)
    puts header.magic
    puts header.version
    puts header.model_name
    puts header.comment
    puts vert_count = header.vert_count
    t_vertex = []
    # 頂点を全て読み込むコードを追加
    vert_count.times do
      t_vertex << bin.read(TVertex)
    end
    puts t_vertex[0].x
    puts t_vertex[0].y
    puts t_vertex[0].z
    puts t_vertex[0].nx
    puts t_vertex[0].ny
    puts t_vertex[0].nz
    puts t_vertex[0].u
    puts t_vertex[0].v
    puts t_vertex[0].bone_num_1
    puts t_vertex[0].bone_num_2
    puts t_vertex[0].bone_weight
    puts t_vertex[0].edge_flag
  end
end