ラベル C の投稿を表示しています。 すべての投稿を表示
ラベル C の投稿を表示しています。 すべての投稿を表示

2011-11-17

dumb raytracer-ish

ダウンロード

ray.zip

gist:1369770

去年できそこないのレイトレーサを作った。オブジェクトの配置がハードコードで、反射を一度しかしていないので3Dエンジンとしては使えない。シェーダの勉強をしていたと思ったらいつのまにか出来上がっていたものだが、これ以上ほうっておくと忘れそうなのでまとめておく。

操作

操作 | 効果
-- | --
左ドラッグ | ライトを操作
マウスホイール | カメラ前進・後退
右ドラッグ | カメラ見回し
右クリック | モード切り替え (鏡面とか)
左クリックしながらマウスホイール | ズーム (視野角の調整)
右クリックしながらマウスホイール | スレッドの増減 (増やすと早くなるかも)
マウスホイールをクリック | リセット
Hキー | ヘルプを隠す

2011-02-14

Thumbs.dbのフォーマット

WindowsのThumbs.dbはOLE Compound DocumentとかStructured Storageという形式でできている。Wordのdocファイルにも使われていて、要はアーカイブの一種らしい。

この形式を解凍する方法自体はメモしない。ここでは内部にどういうファイルが入っているかだけ書く。

これを読み込むライブラリは、Rubyではruby-oleジェム、PerlならWin32::OLE、JavaならApache POIのPOIFS、CならCOMのIStorageとかPOLEというライブラリがある。

ディレクトリの内容

そのたぐいのライブラリで解凍すると、中身のディレクトリはこうなっている。フォルダはなく、いくつかバイナリファイルが入っているだけ。

  • Catalog
  • 01
  • 1
  • 11
  • 2
  • 21
  • 3
  • 4
  • 5
  • ...

内容としては、名前が数字のファイルがJPEGファイルにヘッダがくっついたもので、Catalogにその数字と実ファイル名の対応付けが記録されている。

各サムネイルにはIDがついている。

不思議なのはIDとファイル名が文字列として反転しているというところ。

idが5のサムネイルは5というファイルに入っているが、idが13のサムネイルは31というファイルに入る。

カタログ (Catalog ファイル)

Catalogのフォーマットは先頭からこう。数値は全てUint32LE。

  • ヘッダが16バイト
    • 4バイト~8バイト目にサムネイル数
  • サムネイル数だけ以下を繰り返し(各エントリのサイズは不定)
    • エントリ全体のサイズ
    • ID
    • 更新日時
    • 何かの数値
    • UTF16LEでファイル名
    • 0でパディング

サムネイル (0, 1, 11, 2, 21 ..)

サムネイル画像のファイルの内容は以下のとおり。

  • ヘッダ (12バイトか16バイト)
  • JPEGファイル

ヘッダの長さは可変というか、12バイトか16バイトかのどちらからしい。

本来ならヘッダにあるタイプを調べるべきなのだろうが、とりあえずJPEGファイルの頭にあるマジックナンバー(0xFF 0xD8)を目印にすればヘッダの内容を読む必要はない。

実装

画像を吐き出すだけのツールを作るなら、流れはこうなる。

  • Structured Storageのライブラリを使ってthumbs.dbを読み込む
  • Catalogファイルを取り出して上のフォーマットで解釈する
  • 各ファイル名についてサムネイルを取り出し、JPEGファイルをその辺に書き出す

これをRubyとC++で書いた。

手抜き

以上はlibforensicsというPythonのライブラリのlf.win.shell.thumbsdbのコードを読んだだけなので、このライブラリを使うのが一番早いかもしれない。

こういった解体処理をする必要があるのは元のファイル名が欲しいときだけで、サムネイル画像を取り出したいだけならまじめに読み込む必要はない。

無圧縮で暗号化もされていないので、thumbs.dbを普通に開き、JPEGのSOI(0xFF 0xD8)とEOI(0xFF 0xD9)を探して次々書き出せばすむ。

(copied from tumblr)

2011-01-07

異種enumの比較を防ぐ

Visual C++ 2010はenum classがない(SP1でもC++0xの機能を増やす予定はないとか)。

でも、enum classがなくても型チェックはある程度できる。

enum WeaponType {
    WEAPON_TYPE_MOCHI,
    WEAPON_TYPE_SALMIAKKI,
};
enum TreatsType {
    TREATS_TYPE_MOCHI,
    TREATS_TYPE_SALMIAKKI,
};
// the trick is here
void operator ==(WeaponType, int);
void operator !=(WeaponType, int);
void operator ==(int, WeaponType);
void operator !=(int, WeaponType);
void operator ==(TreatsType, int);
void operator !=(TreatsType, int);
void operator ==(int, TreatsType);
void operator !=(int, TreatsType);
void test() {
    if (WEAPON_TYPE_MOCHI != WEAPON_TYPE_SALMIAKKI) { // ok
        eat();
    }
    if (WEAPON_TYPE_MOCHI == TREATS_TYPE_SALMIAKKI) { // error!
        scream();
    }
}

enum#defineconstの羅列より短いから使っているだけなので、自分は使わないだろう」と思っていたが、昨日別種のenumを比較するコードを書いてバグを出し、30分悩んだ。なので少なくとも型チェックのところは欲しいと思うようになった。

type-safe enumのようなクラスでラップするという方法は確実だが、文字数がとても多いのでそらで書き下せる自信がない。「enumのまま型チェックをする」方法を考えていたら上記の方法を思いついた。

つまり、「比較のoperatorを定義して、実装しない」という方法だ。

最初は operator ==(WeaponType, TreatsType); のように定義していたが、 enum の数を増やすと爆発することに気づいて int に変えた。 int でないほうがエラーは多少読みやすい。

返り値を void でなく bool で定義すると、リンク時のエラーになる。 void で定義するとコンパイル時にエラーが出てくれるのでそうした。

2010-11-28

jom: 並列nmake

jomというQtの作っているビルドツールを見つけた。

Visual C++付属のmakeであるnmakeのクローンらしい。違いはマルチコア用に並列ビルドができること。バイナリが単独で公開されているので最近利用している。

gmakeは-j 5とすると5プロセスで並列でビルドを走らせてくれるが、nmakeは未だにそのサポートがない。cl /MP a.c b.cというオプションで並行でコンパイルはしてくれるが、makeを使う場合ソースファイルはひとつずつしか処理されないので、このオプションは使えない。

  • MSVCでプログラムを作っているのに
  • Visual Studioではなくnmakeを使っていて
  • nmake用のMakefileを捨てたくないが
  • コンパイル速度を上げたい

というかなりニッチな需要を満たしてくれる。(というか、本来はQtユーザ用なのだと思う)

ベンチマーク

手元の自作ゲームを一からビルドする時間を計ってみた。3GHzのCore 2 Duoで試した。

『体力制チェス』 (総計9461行、53ヘッダ+47ソース=100ファイル)

--nmakejom
プリコンパイルヘッダなし25.2 秒14.23 秒
プリコンパイルヘッダあり5.0 秒3.6 秒

『加速度センサー小品集』 (総計10067行、51ヘッダ+57ソース=108ファイル)

--nmakejom
プリコンパイルヘッダなし33.6 秒18.5 秒
プリコンパイルヘッダあり7.2 秒4.9 秒

それなりに効果はあるようだ。(ディスクキャッシュの話があるので細かい数字は信用できないが)

移行

クローンとはいえ、既存のMakefileを全くそのまま使えたわけではない。

依存関係を見て並列的に処理できるところを分けるので、依存関係をきちんと設定していないと順不同になるところが出てくる。最初に試したときはmkdirが偶然うまくいっていた所がつまづいた。

Makefile内でINCLUDE環境変数を書き換えてインクルードパスを無理やり設定していたが、その方法が通じなかった。CFLAGSに直接追加することで解決した。INCLUDEをMakefile内で設定してもコンパイラに伝わらないようだ。

下位互換性はあるので、とりあえず仲間内では自分だけ使おうと思っている。

Nov 28th, 2010 11:10pm
(copied from tumblr)

2010-09-01

マンデルブロ/ジュリア/バーニングシップ集合ビューア

Mandelbrot

よくあるマンデルブロー集合のビューアを作った。マウスだけでつかんで4次元で切片を動かせる。緑が発散までの回数、赤青は発散した向き。

ダウンロード

mandelbrot.zip

gist:525284

操作

操作効果
ドラッグ移動
ダブルクリック移動
マウスホイール拡大・縮小
右ドラッグ定数の調整
右クリックモード切り替え (ジュリア集合とか)
左クリックしながらマウスホイール繰り返し回数の調整
右クリックしながらマウスホイールモード切り替え (ジュリア集合とか)
マウスホイールをクリックリセット

(copied from tumblr)

2010-05-04

C言語のCって何?

「何の略でもない」というのが本来の答えだが、元をたどると3つくらい答えがあるらしい。(『C++の設計と進化』から)

「B言語の次」

「Bって何?」

「BCPLをインタプリタに設計し直したもの」

「BCPLって何?」

「Basic CPLの略」

「Basic CPLって何?」

「CPLという言語を設計し直したもの」

「CPLって何?」

「C. Programming Language の略。Cは以下のどれか」

  • Cambridge (開発した大学の片方の名前)
  • Christopher (設計者の名前)
  • Combined (公式にはこれ。「共同開発」の意)

結局C言語の元はC言語ということになる。

途中の説明を飛ばして「C言語のCからだよ」と言えばややこしくなっていいかもしれない。

(copied from tumblr)

2010-03-23

プレーンテキストの画像形式

少し前から「プレーンテキストの画像形式」というものを探していた。

レイトレーシングなど、絵が出力結果であるプログラムを作って遊んでいると、レンダリングの結果を出す先に困ることがある。

画面表示のできるライブラリを持ってくるのも大仰だ。画像に保存したいところだ。しかも、printfとかで適当に。

BMPの構造体の定義や、PNGやGIFのアルゴリズムを空で書き下すには修行が必要だ。(windows.hは反則)

UNIX系列であればPNMというかなり理想的な形式がある。しかし、残念ながらWindows付属のビューアでは見られない。

SVG形式も考えたが、これはビットマップには向かない。rectを一面に並べる変換器を作ってみたら200KB程度の画像が9MBに膨れ上がった。

サイズはテキストの時点である程度諦めるべきところだが、どちらにしろ表示が極端に重たかった。

SVGの形式を眺めていて、HTMLで一時期流行った遊びを思い出した。

「tableタグでbgcolorを指定したtdをひたすら並べる」

<code><html>
  <head>
    <style>
      tr{height:1px}
      td{width:1px}
    </style>
  </head>
  <body>
    <table border="0" cellpadding="0" cellspacing="0">
      <tr><td bgcolor="#000000"></td><td bgcolor="#000000"></td><td bgcolor="#000000"></td><td...
      <tr><td bgcolor="#000000"></td><td bgcolor="#000000"></td><td bgcolor="#000000"></td><td...
      ...
    </table>
  </body>
</html>
</code>

本当にfprintfしか使わない実装。

void dump(int w, int h, const char *pixels, FILE *fp)
{
    int x, y;

    fprintf(fp, "<html><head><style>tr{height:1px}td{width:1px}</style></head><body><table cellpadding=0 cellspacing=0 width=%d height=%d>", w, h);

    for(y=0; y<h; y++)
    {
        fprintf(fp, "<tr>");

        for(x=0; x<w; x++)
        {
            fprintf(fp, "<td bgcolor=#%02x%02x%02x></td>", pixels[x + y * w], pixels[x + y * w + 1], pixels[x + y * w + 2]);
        }

        fprintf(fp, "</tr>");
    }

    fprintf(fp, "</body></html>");
}

これでとりあえずブラウザに表示させてプリントスクリーンすれば画像になる。

いまどきならCanvasでImageDataなどを使うのかもしれない。

(copied from tumblr)