2009年06月02日

Blenderにvectexを組み込む

前回、vectexが使用しているライブラリをSconsを使用したBlenderのビルドの過程に組み込みました。今回は、それらの組み込んだライブラリを使用する形でvectex本体の方をBlenderに組み込んでいきたいと思います。

基本的には、5/6の記事で書いた「プロシージャルテクスチャの追加」を参考にして作業を進めていきます。
修正するBlenderのソースファイルもほとんど同じものとなります。
  1. 変数の定義: DNA_texture_types.h
  2. 描画処理: texture.c
  3. UIの作成: buttons_shading.c
元になるvectexのソースファイルはvectex.c一つだけです。
実際にプログラミングを行っている時はBlender2.48aのソースコードを使っていましたが、つい最近Blender2.49がリリースされましたので、この機会にソースコードをBlender2.49を使ったものに書き直しています。

こちら(Blender_modified_src090602.zip)にソースコードをまとめておきます。
実行ファイルの方はブログのサーバーで使用できる容量の追加申請中のため、次回にアップロードするつもりです。(Seesaaでは2GBまで使用できるのですが、実際には100MB単位で割り当てられます。現在残量が20MBくらいしかありません。)

修正内容がかなり多く、全部をまとめて説明すると長くなりすぎると思いますので、今回と次回の2回に分けることにしました。今回はvectex.cの内容をBlenderの内部に移す部分のみに絞り、次回は追加したソースコードを実際に動くようにするために必要な修正内容を書くつもりです。

○変数の定義(/blender/source/blender/makesdna/DNA_texture_types.h)
Blenderのテクスチャのパネルに表示されるパラメータを保持する変数は、設定した値を.blendファイルに保存したり、IPOカーブで編集できるようにしたり、pythonから操作できるようにしたりといった特別な処理が必要なため、「Tex」という一つの構造体の中にまとめられています。

今回は、vectex.cの84行目から100行目にかけて記述されているCast構造体のメンバ変数全てを、Tex構造体のメンバとして追加します。
それ以外に、vectex.cの38行目から53行目にかけて記述されているTile構造体、Instance構造体という2つの構造体をTex構造体経由で参照できるようにポインタを追加します。
これらの構造体については.blendファイルに保存したりする必要はないので、別の場所に記述した方がいいのかもしれませんが、今回は分かりやすさ優先で同じ場所にまとめてみました。

BlenderのソースコードはほとんどがCで書かれていて、変数や構造体、関数の名前などにvectexで使用されているものをそのまま使うと既存の名前と重複してしまう可能性があるため、頭に「Vtex」というような文字列を追加することにしました。

ヘッダファイルを追加しています。
struct Tex;
struct Image;
struct PreviewImage;
struct ImBuf;
struct VtxTile;
struct VtxInstance;

構造体を2つ追加しています。
typedef struct VtexTile
{
    unsigned char *image;
    unsigned int   age;
    float pad;
} VtexTile;

typedef struct VtexInstance
{
    void         *backend_data;
    int           tile_set_max_power;
    int           tile_memory;
    unsigned int  timestamp;
    unsigned char current_base_color[4];
    char          current_file_name[160];
    struct VtexTile         *tile_set;
} VtexInstance;

Tex構造体に変数を追加します。
typedef struct Tex {
    ID id;
   
    float noisesize, turbul;
    float bright, contrast, rfac, gfac, bfac;
    float filtersize;
    ...   
    /* vectex */

    int vtex_enable, vtex_mipmap, vtex_interpol, vtex_tex_level, vtex_mem_max, vtex_mem;
    unsigned char vtex_base_color[4];
    char vtex_file_name[160];


    float pad1;

    struct VtexInstance *vtex_instance_data;
   
    struct ImageUser iuser;
   
    struct bNodeTree *nodetree;
    struct Ipo *ipo;
    struct Image *ima;
    struct PluginTex *plugin;
    struct ColorBand *coba;
    struct EnvMap *env;
    struct PreviewImage * preview;
   
    char use_nodes;
    char pad[7];
   
} Tex;

vectexのCast構造体には、label_dummyという変数がありますが、これらは必要なくなるため省略しました。
また、テクスチャのファイル名を保持するchar型のfile_name[64]という配列は、より長いファイル名を格納できるようにサイズを64から160に変更してみました。
flat型のpad1という変数は、構造体を8byteのアライメントに合わせるためのダミーデータです。

さらに、このファイルの最後の方にある定数の定義にもいくつか修正を加えます。
/* **************** TEX ********************* */

/* type */
#define TEX_CLOUDS        1
...
#define TEX_DISTNOISE    13
#define TEX_VECTEX        14
こちらはテクスチャタイプの判別用の定数です。
/* **************** vectex ******************* */
#define VTEX_TILE_SIZE       256
#define VTEX_TILE_SIZE_POWER 8
#define VTEX_TILE_BORDER     1
#define VTEX_MAX_TIMESTAMP   5000

/* Special tile age values */
enum {VTEX_UNUSED = 0, VTEX_CONST_COLOR, VTEX_START_VALUE};

これらは、vectexで使用されている定数です。名前の頭に「VTEX_」を加えています。

○描画処理 (/blender/source/blender/render/intern/source/texture.c)
このファイルにvectex.cの関数をすべて組み込んでしまいます。
まず、ヘッダファイルのインクルード文を追加します。
#include "MEM_guardedalloc.h"
#include "vectex.h"

続いて関数です。
ほとんどの部分はコピーアンドペーストでそのまま張り付けただけですが、関数名、変数名の頭に「vtex_」を追加している部分をすべて修正しています。また、Cast構造体のメンバの変数を使っている部分はTex構造体に変更してあります。
あまりに長くなりすぎるので、ブログの記事中には目立つ修正部分のみを取り上げます。

・メモリ処理関数の変更
テクスチャプラグインのvectexではBlenderからエクスポートしている関数を使用していますが、それらをすべてBlenderの内部用の関数名に修正します。
ただし、名前は変わっても実際に呼び出されているのは同じ関数です。

void create_tile_set(Instance *instance)
void create_instance(Cast *cast)
これらの関数ではメモリ確保の部分にテクスチャプラグイン用にエクスポートされているmallocN()を使っている部分があったので、Blenderの内部用のMEM_mallocN()に書き換えました。
void vtex_create_tile_set(VtexInstance *instance)
{
    ...
    instance->tile_set = (VtexTile *) MEM_mallocN(sizeof(VtexTile) * size, "vectex:tileset");
    ...
}

void limit_tile_set(Instance *instance, int maximum)
void destroy_tile_set(Instance *instance)
void destroy_instance(Cast *cast)
int get_tile(Instance *instance, int x, int y, int power)
これらの関数では、メモリの解放の関数を使う部分でmemory_free()をMEM_freeN()に修正しています。
void vtex_limit_tile_set(VtexInstance *instance, int maximum)
{
        ...
        MEM_freeN(instance->tile_set[index].image);
        ...
}
・スレッドのロック
テクスチャプラグインのvectexでマルチスレッドレンダリングに対応するためには、スレッドをロックする関数をsample()という関数内に記述する必要がありました。このスレッドをロックする関数もBlender内部用のものを使用します。
void vtex_sample(VtexInstance *instance, float *texvec, int power, int interp,
            double *pr, double *pg, double *pb)
{
        ...       
        BLI_lock_thread(LOCK_IMAGE);
        int index = vtex_get_tile(instance, x, y, power);
        BLI_unlock_thread(LOCK_IMAGE);
        ...       
}

・vectex()関数
vextex()という関数は元はplugin_tex_doit()という関数名でしたが、Blenderの内部では各プロシージャルテクスチャの名前を使っているためこのように変更しました。

テクスチャプラグインではplugin_tex_doit()関数にint型のstypeという変数が渡されていて、プラグインのパネルのモード切り替えに使用しています。Blenderの内部ではこれに相当する変数は特に用意されていません。
もともとvectexではstypeは使用していませんが、plugin_tex_doti()関数の一番最初にこのstypeを含む行があるのでコメントアウトしています。
    /* stype = 0;  prevent unused variable warning */
テクスチャプラグインの関数とBlenderの内部のテクスチャ関数では計算結果を返すために使用するデータが少し違っています。
テクスチャプラグインではfloat型のresultという配列を使用していますが、Blender内部のテクスチャ関数ではTexResultという構造体を使っています。

result[0]    : texres->tin
result[1]    : texres->tr
result[2]    : texres->tg
result[3]    : texres->tb
result[4]    : texres->ta
static int vectex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
        ...
        /* Return a black pixel */
        texres->tin = texres->ta = 1.0;
        texres->tr = texres->tg = texres->tb = 0;
        ...
        /* Return a red pixel */
        texres->tin = texres->tr = texres->ta = 1.0;
        texres->tg = texres->tb = 0;
    ...

    texres->tin = 1.0;
    texres->tr = r;
    texres->tg = g;
    texres->tb = b;
    texres->ta = 1.0;
   
    return (TEX_INT | TEX_RGB);
}
・multitex()関数
この関数の中にテクスチャの処理を行うvectex()関数を呼び出すコードを追加しています。
static int multitex(Tex *tex, float *texvec, float *dxt, float *dyt, int osatex, TexResult *texres)
{
    ...
    case TEX_VECTEX:
        retval = vectex(tex, texvec, dxt, dyt, osatex, texres);
        break;

    ...
}
実は、色々とあって上記のような修正を加えても、いくつかの関数はこのままではきちんと動きません。
どの関数にどんな修正が必要なのかは、次回の記事で詳しく書くつもりです。
(2009/6/4 追記:一部修正内容が抜けていたのを修正しました。)

○/source/blender/render/intern/SConscript
上記の「/source/blender/render/intern/source/texture.c」にvectex.cのコードを追加したため、コンパイル時に読み込むインクルードファイルを追加するようにビルド設定ファイルにも修正が必要となります。
#!/usr/bin/python
Import ('env')

cflags=''
sources = env.Glob('intern/source/*.c')

incs = 'intern/include #/intern/guardedalloc ../blenlib ../makesdna'
incs += ' extern/include ../blenkernel ../radiosity/extern/include ../imbuf'
incs += ' ../include ../blenloader'
incs += ' #/extern/aggsvg'

defs = []
....

○UI(ユーザーインターフェイス)の作成(/source/blender/src/buttons_shading.c)
・texture_panel_vectex()関数(line:46-768)
vectex用のパネルの設定を行う処理です。テクスチャプラグインでは構造体VarStructの配列varstr[]に各ボタンの設定を記述していました。そのパラメータをほとんどそのままuiDefBut()関数の引数に設定する感じです。ただし、デフォルト値についてはuiDefBut()関数には設定することができないようです。
static void texture_panel_vectex(Tex *tex)
{
    uiBlock *block;
    block= uiNewBlock(&curarea->uiblocks, "texture_panel_vectex", UI_EMBOSS, UI_HELV, curarea->win);
    if(uiNewPanel(curarea, block, "vectex", "Texture", 640, 0, 318, 204)==0) return;
    uiSetButLock(tex->id.lib!=0, ERROR_LIBDATA_MESSAGE);

    uiBlockBeginAlign(block);
    uiDefButI(block, TOG, B_TEXPRV, "Enable", 10, 180, 150, 18, &tex->vtex_enable, 0, 1, 0, 0, "Enable vector texture (disabling frees memory)");
    uiDefButI(block, TOG, B_TEXPRV, "MipMap", 10, 160, 150, 18, &tex->vtex_mipmap, 0, 1, 0, 0, "Uses mipmap averaging");
    uiDefButI(block, TOG, B_TEXPRV, "Interpol", 10, 140, 150, 18, &tex->vtex_interpol, 0, 1, 0, 0, "Interpolates nearby pixels");
    uiDefButI(block, TOG, B_TEXPRV, "Tex Level", 10, 120, 150, 18, &tex->vtex_tex_level, 0, 1, 0, 0, "Displays texture detail as hue");
    uiDefButI(block, NUM, B_TEXPRV, "Mem Max", 10, 100, 150, 18, &tex->vtex_mem_max, 0, 200, 10, 0, "Maximum memory to use (in megabytes, 0=no limit)");
    uiBlockEndAlign(block);
   
    uiBlockBeginAlign(block);
    uiDefButI(block, NUM, B_TEXPRV, "Mem:", 160, 180, 150, 18, &tex->vtex_mem, 0, 999, 10, 0, "Displays current memory being used (in megabytes)");
    uiDefBut(block, LABEL, 0, "Base Color", 160, 160, 150, 18, 0, 0.0, 0.0, 0, 0, "Base texture color");
    uiDefBut(block, COL|CHA, B_TEXPRV, "", 160, 140, 150, 18, &tex->vtex_base_color, 0, 0, 0, 0, "Base texture color");
    uiDefBut(block, LABEL, 0, "File Name", 160, 120, 150, 18, 0, 0.0, 0.0, 0, 0, "SVG file name");
    uiDefBut(block, TEX, B_TEXPRV, "", 160, 100, 150, 18, &tex->vtex_file_name, 0.0, 159.0, 0, 0, "SVG file name");
    uiBlockEndAlign(block);
}

・texture_panel_texture()関数(line:1727)
Textureパネルでテクスチャを選択するためのメニューに「vectex」の項目を追加します。
static void texture_panel_texture(MTex *actmtex, Material *ma, World *wrld, Lamp *la, bNode *node, Brush *br, SculptData *sd)
{
        ...
        if( !tex->use_nodes ) {
            sprintf(textypes, "Texture Type %%t|None %%x%d|Image %%x%d|EnvMap %%x%d|Clouds %%x%d|Marble %%x%d|Stucci %%x%d|Wood %%x%d|Magic %%x%d|Blend %%x%d|Noise %%x%d|Plugin %%x%d|Musgrave %%x%d|Voronoi %%x%d|DistortedNoise %%x%d|Vectex %%x%d", 0, TEX_IMAGE, TEX_ENVMAP, TEX_CLOUDS, TEX_MARBLE, TEX_STUCCI, TEX_WOOD, TEX_MAGIC, TEX_BLEND, TEX_NOISE, TEX_PLUGIN, TEX_MUSGRAVE, TEX_VORONOI, TEX_DISTNOISE, TEX_VECTEX);
            uiDefBut(block, LABEL, 0, "Texture Type",        160, 150, 140, 20, 0, 0.0, 0.0, 0, 0, "");
            uiDefButS(block, MENU, B_TEXTYPE, textypes,    160, 125, 140, 25, &tex->type, 0,0,0,0, "Select texture type");
        }
        ...
}
・texture_panels()関数(line:4677-4679)
Textureパネルでvectexが選択されたときに、vectexのパネルを表示するための処理をする関数texture_panel_vectex()を呼び出す部分です。
void texture_panels()
{
    ...
            switch(tex->type) {
            case TEX_IMAGE:
                texture_panel_image(&tex->ima, &tex->iuser);
                texture_panel_image_map(tex, mtex);
                break;
            ...
            case TEX_VECTEX:
                texture_panel_vectex(tex);
                break;

            }
        }
    }
}
これでvextex.cのソースコードをBlenderに組み込む作業自体は完了しましたが、このままコンパイルしてもエラーが出てしまって動きません。
さらに、そのエラーを修正してコンパイルが完了するようになっても、それだけではvectexの機能を使えるようになりません。
次回、あれこれ必要な修正の内容について、記事に書きたいと思います。
posted by mato at 21:57| Comment(0) | Blender Vectex | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。