2009年05月21日

Blenderにライブラリ(AGG、Expat)を組み込む

今回からBlender本体にSVGテクスチャプラグインvectexの機能を組み込む作業に取りかかります。まずは、vectexが使用している2つのライブラリ、AGGとExpatをBlenderのコードから利用できるようにしてみます。

Blenderには様々なライブラリが使用されています。
分かりやすいところではJpeg、PNGなどの画像ファイルを扱うためのライブラリや、動画の処理をするFFmpegなどが使われています。
Blenderのソースコードの中に入っていて静的にリンクされているものと、システムにインストールされているDLL、シェアードライブラリに動的にリンクされるものがあります。

ライブラリを組み込む場合、このどちらの方法でリンクするかによって必要な処理が若干変わってきますが、今回の場合は、
  1. AGGはもともとDLL、シェアードライブラリとして使うことを想定したライブラリではないので、静的リンクで使用する。
  2. Expatは動的リンクを使うことが可能だが、もともとvectexで静的リンクで使用しているので、同じように静的リンクで使用する。
という感じで、どちらのライブラリもソースコードをBlenderの一部に組み込んで、Blenderのビルド時にまとめてコンパイルするようにします。

vectexを組み込む改造版BlenderのビルドにはSconsを使用する方針です。
とりあえずはSconsの設定ファイルだけを修正していき、CMakeなどの設定ファイルについては余裕ができたら少しずつ対応していくつもりです。

ちなみに今回もLinuxのみに限定して話を進めていきます。
実は、vectexのプラグインについては、Windows上のSconsではまだコンパイルに成功していません。BlenderについてはなんとかMinGW上のSconsでビルドできていますので、改造版BlenderがLinuxで動作できるようになったらWindowsにも対応できると思います。

使用するBlenderのバージョンは今のところ2.48aですが、2.49がリリースされた時点でそちらに移行していくつもりです。
今回作成または修正した部分のソースコードをこちら(src090521.zip)にまとめました。

○ライブラリのソースコードを組み込む
Sconsでビルドを行うための設定ファイルの修正を始める前に、まずAGG、ExpatのソースコードをBlenderのソースディレクトリのどこに置くのかを決める必要があります。

Blenderのトップディレクトリにはextern、internというディレクトリがあり、その中にいくつかのライブラリが置かれています。
どのようなものがどちらに置かれるべきなのか詳しいことはよく分からないのですが、とりあえずexternディレクトリの下に置くことにしてみます。後で別の場所に置くべきだと分かれば、変更するかもしれません。
pic090521_01.jpg

vectexが使用するライブラリ自体はAGG、Expatの2つなのですが、AGG SVG Viewerの部分のソースコードもライブラリのように扱ってしまった方が構成がすっきりするように思いますので、今回はこの部分をaggsvgというディレクトリにまとめることにします。

ついでにvectex本体のソースコードファイル3つのうちvectex_agg.cpp、vectex.hの2つも、ここに入れてしまうことにします。
vectex_agg.cppは、その拡張子を見て分かる通り「C++」のソースコードですが、Blenderのソースコードは外部のライブラリやゲームエンジン以外は基本的に「C」のソースコードで書かれています。C++のコードとCのコードが混在している場合、ビルド時のコンパイルオプションなどが若干面倒になる可能性もあるため、ちょっと不自然な感じもしますが、今回はこのような感じにファイルを配置することにしました。

ソースコードの配置については、後はvextex.cのソースコードをBlenderのプロシージャルテクスチャをまとめてあるソースファイル「blender/source/blender/render/intern/source/texture.c」の中にまるごと組み込むだけとなります。
pic090521_02.jpg

○Sconsのビルド用設定ファイル

BlenderをSconsでビルドするための設定ファイルは、トップディレクトリにあるSConscriptファイル以外にもいくつか重要なファイルがあります。
Blenderのトップディレクトリにある「config」フォルダには、ビルドを行う各OSに対応するための「.py」(Python)ファイルがあります。また、同じくトップディレクトリにある「tools」フォルダにもいくつかの「.py」ファイルがあって、こちらもSconsのビルドの時に使用されます。

新規にライブラリを追加するために修正が必要となるのは、「config」フォルダ内のファイル(今回はLinux限定なのでlinux2-config.pyのみ)、「tools」フォルダ内のBlender.pyとbtools.pyです。
pic090521_04.jpg pic090521_05.jpg

具体的にどこをどう修正すればいいかについては、Blenderトップディレクトリにある「doc」フォルダのblender-scons-dev.txtというファイルに詳しく書かれています。
pic090521_03.jpg

○config/linux2-config.py
本来はすべてのプラットフォームでビルドできるようにするためconfigフォルダ内のすべてのXXX-config.pyファイルを修正するはずなのですが、今回はとりあえずLinux以外については後回しとしてlinux2-config.pyのみを修正することにします。
...
#for vectex SVG texture
WITH_BF_VECTEX = True
BF_AGGSVG = '#extern/aggsvg'
BF_AGGSVG_INC = '${BF_AGGSVG}/include'
BF_AGGSVG_LIB = 'extern_aggsvg'
BF_AGGSVG_LIBPATH = '${BF_AGGSVG}/lib'

BF_AGG = '#extern/agg'
BF_AGG_INC = '${BF_AGG}/include'
BF_AGG_LIB = 'extern_agg'
BF_AGG_LIBPATH = '${BF_AGG}/lib'

BF_EXPAT = '#extern/expat'
BF_EXPAT_INC = '${BF_EXPAT}/include'
BF_EXPAT_LIB = 'extern_expat'
BF_EXPAT_LIBPATH = '${BF_EXPAT}/lib'

...
AGG、EXPAT、AGGSVGのそれぞれについて、ライブラリのベースとなる場所、インクルードファイルの場所、ライブラリ名、ライブラリファイルの場所を指定するためのSconsのオプションを追加しています。
また、今回追加するライブラリをビルド時にオン/オフ切り替えできるようにするためのオプションとしてWITH_BF_VECTEXというものも追加しました。
他のライブラリを見ると、それぞれのライブラリ毎にWITH_BF_XXXオプションを付けているようですが、今回はどれかひとつだけをオフにできるようにしても意味がなさそうなので、ひとつにまとめてしまいました。

○tools/btools.py

このファイルにはライブラリをビルドするためのオプションを全て列挙している記述が2ヶ所ありますので、今回追加したオプションの分を追加します。
def validate_arguments(args, bc):
    opts_list = [
            ...
            'WITH_BF_VECTEX', 'BF_AGGSVG', 'BF_AGGSVG_INC', 'AGGSVG_LIB', 'AGGSVG_LIBPATH',
            'BF_AGG', 'BF_AGG_INC', 'BF_AGG_LIB', 'BF_AGG_LIBPATH',
            'BF_EXPAT', 'BF_EXPAT_INC', 'BF_EXPAT_LIB', 'BF_EXPAT_LIBPATH',

            ...
def read_opts(cfg, args):
    localopts = Options.Options(cfg, args)
    localopts.AddOptions(
        ...
        (BoolOption('WITH_BF_VECTEX', 'Use vectex if tue', True)),
        ('BF_AGGSVG', 'AGGSVG base path', ''),
        ('BF_AGGSVG_INC', 'AGGSVG include path', ''),
        ('BF_AGGSVG_LIB', 'AGGSVG library', ''),
        ('BF_AGGSVG_LIBPATH', 'AGGSVG library path', ''),
   
        ('BF_AGG', 'AGG base path', ''),
        ('BF_AGG_INC', 'AGG include path', ''),
        ('BF_AGG_LIB', 'AGG library', ''),
        ('BF_AGG_LIBPATH', 'AGG library path', ''),
   
        ('BF_EXPAT', 'EXPAT base path', ''),
        ('BF_EXPAT_INC', 'EXPAT include path', ''),
        ('BF_EXPAT_LIB', 'EXPAT library', ''),
        ('BF_EXPAT_LIBPATH', 'EXPAT library path', ''),

        ...
○tools/Blender.py
このファイルでは、ビルド時のライブラリオプションに関する記述を修正します。
こちらはライブラリの場所の記述です。
## TODO: static linking
def setup_staticlibs(lenv):
    statlibs = [
        #here libs for static linking
    ]
    ...
    if lenv['WITH_BF_VECTEX']:
        libincs += Split(lenv['BF_AGGSVG_LIBPATH'])
        libincs += Split(lenv['BF_AGG_LIBPATH'])
        libincs += Split(lenv['BF_EXPAT_LIBPATH'])

    ...
こちらはライブラリ名です。
def setup_syslibs(lenv):
    syslibs = [
       
        lenv['BF_JPEG_LIB'],
        lenv['BF_PNG_LIB'],
        lenv['BF_ZLIB_LIB']
        ]
    ...
    if lenv['WITH_BF_VECTEX']:
        syslibs += Split(lenv['BF_AGGSVG_LIB'])
        syslibs += Split(lenv['BF_AGG_LIB'])
        syslibs += Split(lenv['BF_EXPAT_LIB'])

    ...
○extern/Sconscript
Sconsの全体に関係する設定ファイルの他に、実際にライブラリのソースファイルを置いた場所にあるSConscriptファイルを修正する必要があります。
WITH_BF_VECTEXがオンのとき、aggsvg、agg、expatのそれぞれの場所に置いたSconscriptファイルを実行します。
#!/usr/bin/python

Import('env')

SConscript(['glew/SConscript'])
...
if env['WITH_BF_VECTEX']:
    SConscript(['aggsvg/SConscript'])
    SConscript(['agg/SConscript'])
    SConscript(['expat/SConscript'])

...
○extern/agg/SConscript
前回の記事でテクスチャプラグインとしてvectexをSconsでコンパイルしたときのSConscriptファイルとはかなり違っています。externフォルダにある他のライブラリのSConscriptを参考にして書き直しました。
#!/usr/bin/python
import sys
import os

Import('env')

sources = env.Glob('src/*.cpp') + env.Glob('gpc/*.c') + env.Glob('src/ctrl/*.cpp')
incs = 'include include/ctrl gpc'
defs = ''
cflags = '-fPIC -c -O3'

env.BlenderLib ( libname='extern_agg',
        sources=sources, includes=Split(incs),
        defines=Split(defs),
        libtype=['blender', 'common'],
        priority=[10, 20], compileflags = Split(cflags))
今回は、各ライブラリのトップディレクトリのSConscriptだけで完結するようにしました。
また、最終的にライブラリを作成する部分はenv.Library()ではなくて、tools/Blender.pyの中にあるBlenderLIb()という関数を使っています。
この関数には、ライブラリ名、ソースファイル、インクルードファイルの場所、コンパイルオプションなどの他に、libtype、priorityという引数を渡しています。
この2つについては、今ひとつよくわからなかったのですが、リンク時に問題が起こった場合に調整するために使用するもので、通常は指定する必要はないようです。

○extern/expat/SConscript
#!/usr/bin/python
import sys
import os

Import('env')

sources = ['lib/xmlparse.c','lib/xmlrole.c','lib/xmltok.c',
    'xmlwf/xmlwf.c','xmlwf/xmlfile.c','xmlwf/codepage.c','xmlwf/unixfilemap.c']
incs = '. lib xmlwf'
defs = ''
cflags = '-fPIC -Wall -Wmissing-prototypes -Wstrict-prototypes -fexceptions -DHAVE_EXPAT_CONFIG_H -c'

env.BlenderLib ( libname='extern_expat',
        sources=sources, includes=Split(incs),
        defines=Split(defs),
        libtype=['blender', 'common'],
        priority=[10, 20], compileflags = Split(cflags))
○extern/aggsvg/SConscript
インクルードファイルの指定に#/intern/guardedallocという指定を追加してあります。
これは、テクスチャプラグインとしてvectexが使用していたメモリ処理関連の関数をBlenderの内部用のものに変更したために、そのメモリ処理の関数のライブラリ用のヘッダファイルの場所を追加しています。
#!/usr/bin/python
import sys
import os

Import('env')

sources = env.Glob('*.cpp')
incs = '. ../agg/include ../expat/lib #/intern/guardedalloc'
defs = ''
cflags = '-fPIC -shared -O -ansi'

env.BlenderLib ( libname='extern_aggsvg',
        sources=sources, includes=Split(incs),
        defines=Split(defs),
        libtype=['blender', 'common'],
        priority=[10, 20], compileflags = Split(cflags))
○extern/aggsvg/vectex.h
テクスチャプラグイン用にエクスポートされているメモリ処理関数を使わなくするために、以下の部分をコメントアウトしてあります。
...
/*
EXT void *memory_alloc(int len, char *str);
EXT void memory_free(void *ptr);

*/

...
○extern/aggsvg/vectex_agg.cpp
Blender内部用のメモリ処理関数が書かれたヘッダファイルをインクルードしています。
vectex.h、vectex.cファイルに書かれているmemory_alloc()を使うのを止めて、MEM_malocN()関数を使うようにしました。
この関数は、テクスチャプラグイン用にutil.hでエクスポートされているmallocN()という関数の本体(/source/blender/blendpluginapi/intern/pluginapi.c)で使用されているのと同じものを使っています。
...
#include "MEM_guardedalloc.h"
...
    /*

    unsigned char          *buf = (unsigned char *)memory_alloc(width * height * 3, "vectex:tile");
    */
    unsigned char          *buf = (unsigned char *)MEM_mallocN(width * height * 3, "vectex:tile");

...

○ビルド
以上のファイルを使って実際にビルドを行うためには、この他にBlender/externディレクトリにagg、expat、aggsvgというフォルダを作成し、vectexのソースコードのフォルダから対応するソースコードをコピーしておく必要があります。
aggsvgディレクトリには、vectexソースコードのトップディレクトリにある「.h」「.cpp」ファイルをすべてコピーします。
pic090521_07.jpg
aggディレクトリには、vectexソースコードのagg-2.5フォルダの中身をまるごとコピーします。
expatディレクトリには、vectexソースコードのexpat-1.95.8フォルダの中身をまるごとコピーします。
pic090521_06.jpg pic090521_08.jpg
これで、Blenderにvectexで使用しているライブラリを組み込む作業が完了しました。

この状態で、とりあえずビルドを実行することができます。
vectexの本体のソースコードはまったく組み込んでいませんので、ビルドの結果できあがるのは普通のBlenderです。
ライブラリのビルドの結果は、Blenderのソースコードディレクトリの外部「build/linux2/lib」にlibextern_agg.a、libextern_expat.a、libextern_aggsvg.aという3つのファイルが作成されていることで確認できます。
pic090521_09.jpg pic090521_10.jpg

次回からは、vectex.cのソースコードをBlenderに組み込んでいく予定です。
posted by mato at 01:20| Comment(0) | Blender Vectex | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

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


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

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