Archive for 7月, 2010

Quake IIIをVisual Studio 2008でビルド

id software(イド・ソフトウェア)、この会社は一人称視点のシューティングゲームをFirst Person Shooter通称FPSと言うジャンルとして広めた。
Wolfenstein 3Dを皮切りにDoomが欧米で大ヒット。
3D時代前夜にQuakeをリアルタイム3DCGでリリース。
少数精鋭主義を貫いたせいか、この前Bethesda Softworksかその親会社のZeniMaxに買収。
「洋ゲー=FPS」の様な状況を作り、今に至る。

で、id softwareは本当に素晴らしいソフト会社で、最新以外のQuakeシリーズのソースコードがGPLライセンスの元リリースされている。
例えばQuake 3はこれ。
ftp://ftp.idsoftware.com/idstuff/source/quake3-1.32b-source.zip
他にもDoom / Doom 2やHexen / Heretic、当然Quake、Quake IIもリリースされているので、興味があったらググってみてもいいかもしれない。

そしてそして、お待たせしました。
本題。
このソース、落として解凍してVCにぶち込んでビルドすれば動くのか?と言う話。
答えはNO!
なので記事に・・・。
で、「luozhiyu – Compile Quake III arena」を参考にやってみましょう、と。
あ、先に書いておくけどQuake 3 Arenaを持ってないと動かないからね!
未確認ながら、Demo版があるから、それでも出来るかも?
Amazonでもほぼ売り切れのようなものだから、Steamで買うという手もある。

と言う前置きはさておき、はじめましょうか。
まず普通に解凍する。
解凍したディレクトリに「code」と言うディレクトリがあるはず。
とりあえずそこを開く。
で、「quake3.sln」を開く。


バックアップは作らなくても良いと思う。
だって、そもそもZipファイルにフルソースがあるし・・・。


これもとりあえず無視して「OK」。

これも消しちゃってOKのはず。

これで変換終了。

履歴を出すとこんな感じ。

ここからコンパイル。
でもいろいろ設定しなきゃいけない。


まず、ソリューションのプロパティでスタートアッププロジェクトを「quake3」にする。

で、ウィンドウ上部中央にあるソリューションの構成が「Debug Alpha」とかの場合は「Debug」に変更する。


「quake3」のプロジェクトのプロパティを開いて、「デバッグ」、「コマンド引数」を

+set fs_cdpath "C:\Program Files\Quake III Arena\" +set r_mode "4"

とかにする。
ここのオプションはQuake3のインストールディレクトリにある「baseq3」ディレクトリにある「q3config.cfg」の設定内容と同様と思われる。
ただ一点違うのはプログラムやらアセットやらへのパス。
それを「fs_cdpath “インストールパス”」としないとゲームが起動しない。
あと、もう一つのオプションは解像度のオプションで、今使っているマシンはこのゲームが発売されて軽く10年は過ぎたくらいの時に組んだから、当時としては考えられないような解像度(1920 x 1200)なので、どうしてもエラーが出た。。
製品版から起動してもエラーが出たので、起動時の解像度を抑えるようにしてみた。
自分の環境ではフルスクリーンで落ちるので、「q3config.cfg」の

seta r_fullscreen "1"

seta r_fullscreen "0"

として抑えた。

ちなみに、ビルドして実行してみるとこんなエラーが出る。

これが出なくてオープニングムービーが始まってCDキーを入力する画面が出たらもう問題ないでしょう。

id softwareらしい無骨なタイトル画面w






こんな感じ。

お粗末。

Post to Twitter

, , , , , , , , ,

No Comments

続・dprintf

前回「Visual CのGUIアプリで「出力」ウィンドウへデバッグメッセージを出す」でのdprintfは文字サイズ固定だったからちょっとどうかなぁ〜と思った次第。
多少は動的にして文字数に余裕を持たせたいところ。

あと、MSのAPIにはprintf_sとかsprintf_sとか、さらにはvsnprintf_sとか「_s」付きのセキュリティ強化版がある。
で、これ使ってエラー出すと完全に止まる。。。
例えばバッファより文字が多かった場合、即止まって怒られて落ちる。
本当はその後にバッファをより多くreallocする予定だったのにも関わらず・・・。
そしてそのエラーの止め方がわからない。。
なので、デバッグと言う名目なので、若干セキュアじゃないvsnprintfを使うことに。
(超後ろ向き。。。)
UNIX系でサポートされてない関数をバカスカ使うのも正直気が引けてたから、これで良いのだ〜♪
・・・なんてね。

とりあえず今回書いたコード。

// debug.h
#define _DPRINTF_MALLOC_ERR_ -100
#define _DPRINTF_ARG_ERR_ -101
#define _DPRINTF_REALLOC_ERR_ -102
int dprintf( const char *format, ...);
// debug.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"
#define _DEBUG_BUFF_BASE_SIZE_ 256
int dprintf( const CHAR *format, ...)
{
va_list argPtr;
char *debugMsgBuffer;
char *tmpMsgBuffer;
int msgLen = 0;
int maxBuffSize = _DEBUG_BUFF_BASE_SIZE_;
va_start( argPtr, format );
debugMsgBuffer = (char *) malloc( maxBuffSize );
if ( debugMsgBuffer == NULL ) {
OutputDebugStringA( "dprintf:malloc error.\n" );
return _DPRINTF_MALLOC_ERR_;
}
if ( format == NULL ) {
OutputDebugStringA( "dprintf:format argument is null.\n" );
return _DPRINTF_ARG_ERR_;
}
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfにてバッファ終端に'\0'が書き込まれない
// 時があったので、strlenでも長さチェックをかける。
// あるいは、この時点でスタックを破壊している可能性もある。
if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;
// メモリが足りないときの処理
while ( msgLen < 0 ) {
maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
if ( tmpMsgBuffer == NULL ) {
free( debugMsgBuffer );
OutputDebugStringA( "dprintf:realloc error.\n" );
return _DPRINTF_REALLOC_ERR_;
}
debugMsgBuffer = tmpMsgBuffer;
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfの'\0'書き忘れ問題をここでも対処。
if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;
}
OutputDebugString( debugMsgBuffer );
free( debugMsgBuffer );
return msgLen;
}

まぁ、コメントの通りなんだけど、

if ( (int) strlen( debugMsgBuffer ) > msgLen ) msgLen = -2;

なんてい言う小賢しい処理を入れてる。
何でかというと、下記のコードを実行してもらいたい。

vsnprintfでおかしくなる。

// debug.cpp
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "debug.h"
#define _DEBUG_BUFF_BASE_SIZE_ 4
int dprintf( const CHAR *format, ...)
{
va_list argPtr;
char *debugMsgBuffer;
char *tmpMsgBuffer;
int msgLen = 0;
int maxBuffSize = _DEBUG_BUFF_BASE_SIZE_;
char test[1024];
int testLen = 0;
setlocale( LC_ALL, "C" );
va_start( argPtr, format );
debugMsgBuffer = (char *) malloc( maxBuffSize );
if ( debugMsgBuffer == NULL ) {
OutputDebugStringA( "dprintf:malloc error.\n" );
return _DPRINTF_MALLOC_ERR_;
}
if ( format == NULL ) {
OutputDebugStringA( "dprintf:format argument is null.\n" );
return _DPRINTF_ARG_ERR_;
}
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
// vsnprintfにてバッファ終端に'\0'が書き込まれない
// 時があったので、strlenでも長さチェックをかける。
// あるいは、この時点でスタックを破壊している可能性もある。
// if ( strlen( debugMsgBuffer ) > msgLen ) msgLen = -2; // ここをコメントアウト
// メモリが足りないときの処理
while ( msgLen < 0 ) {
{ // debug
testLen = sprintf( test, "maxBuffSize appended from \"%d\" to", maxBuffSize );
maxBuffSize += _DEBUG_BUFF_BASE_SIZE_;
sprintf( &test[testLen], "\"%d\".\n", maxBuffSize );
OutputDebugStringA( test );
} // debug end
tmpMsgBuffer = (char *) realloc( debugMsgBuffer, maxBuffSize );
if ( tmpMsgBuffer == NULL ) {
free( debugMsgBuffer );
OutputDebugStringA( "dprintf:realloc error.\n" );
return _DPRINTF_REALLOC_ERR_;
}
debugMsgBuffer = tmpMsgBuffer;
msgLen = vsnprintf( debugMsgBuffer, maxBuffSize - 1, format, argPtr );
{ // debug
sprintf( test, "maxBufferSize = \"%d\"\n msgLen = \"%d\"\n  strlen( debugMsgBuffer ) = \"%d\"\n", maxBuffSize, msgLen, strlen( debugMsgBuffer ) );
OutputDebugStringA( test );
} // debug end
// vsnprintfの'\0'書き忘れ問題をここでも対処。
// if ( strlen( debugMsgBuffer ) > msgLen ) msgLen = -2; // ここをコメントアウト
}
OutputDebugString( debugMsgBuffer );
free( debugMsgBuffer );
return msgLen;
}

さっきの小賢しいコード2カ所を撤去してメモリを何バイト取得し、文字列の長さはいくらで、実際の文字列の長さはいくらかを表示しているコードも入ってる。
これを額面通り

dprintf( "hoge = %5d\n", hoge );

とか文字数を変えて実行してみると、変な文字が付いてくる可能性がある。
自分の環境では

glnWidth =  1432	glnHeight =   815

を期待したところ、

glnWidth =  1432	glnHeight =   815
ォォォォォォォォォ

と言うようなゴミが付いてきた。
どうやら境界線ギリギリで書き込みを行う場合に’\0’が書き込まれていないような気もする。
とは言え、vsnprintfの第2引数を-1から-2に変えたところで同様のエラーが起きる。
個人的には手詰まり。
なので、本当に文字処理をプログラム中で扱うときはこの関数は使えない。。。
対処できないし、こんなの。
strlenによるネガティブな対処で良ければいくらでもやるけど、これ、正解じゃないよね?
そんなわけで、dprintfは前のバージョンの法が良かったのかもしれないと思えてきたり・・・。
(で、でも、文字数制限は無いぞ!と、自分を擁護しつつ、こちらを改良して行くことに。。。)

お粗末。

Post to Twitter

, , , , ,

No Comments