そうだ、Rubyをやろう(2日目)
まあ、とにかく何か作ってみようじゃないか。
最初なので、題材としては数十行程度で書けるものが良い。
う〜ん、そうさね
私としては、Rubyをより良いPerlとして使いたいので、なんか適当なテキスト処理をやってみたい気がする。そこで思い立ったのが、前にC++でやったXFile読み込み。あれはCでやるよりも、最初からもっと読み込み易いように整形されてたら良かったなぁという思いがある。そこで、単一のXFileから、頂点座標、頂点インデックス、UV座標を別々のCSVファイルに出力するRubyスクリプトを書いてみることにした。
(XFileの構造についてはこちら参照)
#!/usr/bin/ruby # Xファイルを読み込んで、 # ・頂点座標(.vtx)と # ・頂点インデックス(.idx)と # ・UV座標(.uvx)を # それぞれ別々のファイルに出力するスクリプトです。 # 元のファイル名から.xのサフィックスを取り除き、 # 上記の括弧内のサフィックスのファイル名で出力します。 # ※ # ・単一テクスチャマッピングのみサポートします(XFileの仕様) # ・Z座標は反転されます # ・頂点インデックスは反対周りに補正されます if ARGV.length == 0 then puts "USAGE:XFile2Csv <in-file-name>" exit 1 end FloatPattern = /[-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ UnsignedPattern = /\d+/ # ファイルからすべての文字列を読み込む in_file_name = ARGV[0] base_name = File.basename in_file_name, ".x" dir_name = File.expand_path(File.dirname(in_file_name)) text = File.open(in_file_name).read # メッシュ情報のみ抜き出す if /^Mesh\s*\{(.*)\}/m =~ text then mesh = $1.strip else puts "Mesh section not found." exit 1 end # 頂点座標の数とインデックス座標の数を取得する # メッシュの最初の行を頂点数とする # 最初の空行の次の行をインデックス数とする end_of_vertices = false vnum = nil inum = nil mesh.each_line {|line| line.strip! unless vnum then vnum = line.split(";")[0].to_i next end if line.empty? then unless end_of_vertices then end_of_vertices = true end next end if end_of_vertices then inum = line.split(";")[0].to_i break end } unless vnum then puts "Unknown number of vertices." exit 1 end unless inum then puts "Unknown number of indices." exit 1 end # 頂点座標を読み込んで出力する vcnt = 0 mesh_tail = "" # 頂点座標より後ろのメッシュ情報を格納する File.open(File.join(dir_name, base_name + ".vtx"), "w") {|f| mesh.each_line {|line| if vnum > vcnt then line.strip! array = line.split(";").select {|token| FloatPattern =~ token} if 3 == array.length then # Z座標反転 array[2] = (array[2].to_f * -1).to_s f.puts array.join "," vcnt += 1 end # 全頂点を読み込んだら、次の行は空行 elsif vnum == vcnt then vcnt += 1 f.puts next # それ以降の部分は別バッファへ else mesh_tail += line end } } # 頂点インデックスを読み込んで出力する icnt = 0 File.open(File.join(dir_name, base_name + ".idx"), "w") {|f| mesh_tail.each_line {|line| line.strip! array = line.split(/;|,/).select {|token| UnsignedPattern =~ token} # 三角形 if 4 == array.length then # 逆周りに変換して出力 f.puts array[1] + "," + array[3] + "," + array[2] icnt += 1 # 四角形の場合は、2つの三角形に分割 elsif 5 == array.length then f.puts array[1] + "," + array[4] + "," + array[2] f.puts array[2] + "," + array[4] + "," + array[3] icnt += 1 end if inum == icnt then f.puts break end } } # テクスチャマッピング情報を抜き出す if /^\s*MeshTextureCoords\s*\{(.*)\}/m =~ mesh_tail then coords = $1.strip else puts "MeshTextureCoords section not found." exit 1 end File.open(File.join(dir_name, base_name + ".uvx"), "w") {|f| coords.each_line {|line| line.strip! array = line.split(";").select {|token| FloatPattern =~ token} if 2 == array.length then f.puts array.join "," end } f.puts }
とりあえず動いた。
ま、まあ・・・
最初ならこんなもんじゃろ・・・