Thursday, January 29, 2015

std::regexを使い、自力でOpenGL(WGL)バインド

WindowsでOpenGLを使う為にはwglGetProcAddress関数でAPIの関数ポインタを収集しなければなりません。文字列処理に長けたスクリプト言語でパーサを作って https://www.opengl.org/registry/ のヘッダからCのソースを生成するのが一般的かと思いますが、Visual Studio 2013でregexがstd::regexに移動していたのでC++だけでやってみることにします。
struct GLFunc
{
GLFunc(){}
GLFunc(const GLFunc& r) {
*this = r;
}
const GLFunc& operator=(const GLFunc& r) {
name = r.name;
decl = r.decl;
caster = r.caster;
return *this;
}
std::string name;
std::string decl;
std::string caster;
};
std::vector<GLFunc> glFuncs;
void ParseHeader(const char* healderFileName, const char* regExp, const char* conventions)
{
char* h = (char*)LoadFile(healderFileName);
std::string str = h;
std::regex pattern(regExp);
auto funcBegin = std::sregex_iterator(str.begin(), str.end(), pattern);
auto End = std::sregex_iterator();
int dist = std::distance(funcBegin, End);
printf("%d functions found in %s\n", dist, healderFileName);
int i = 0;
for (auto it = funcBegin; it != End; it++) {
std::smatch m = *it;
if (m.size() < 4) {
continue;
}
GLFunc func;
func.name = m[2].str();
func.decl = m[1].str() + "(" + conventions + "*" + m[2].str() + ")" + m[3].str();
func.caster = m[1].str() + "(" + conventions + "*)" + m[3].str();
glFuncs.push_back(func);
printf("\r%d/%d", ++i, dist);
}
printf("\n");
free(h);
}
int _tmain(int argc, _TCHAR* argv[])
{
ParseHeader("glheaders/glcorearb.h", "^GLAPI\\s+([\\w\\s\\*]+)APIENTRY\\s+(gl\\w+)\\s*(\\(.*\\))", "APIENTRY");
ParseHeader("glheaders/wglext.h", "^(\\w+(?:\\s+\\w+)*\\s+)WINAPI\\s+(wgl\\w+)\\s*(\\(.*\\))", "WINAPI");
return 0;
}
view raw wgl_grabber.cpp hosted with ❤ by GitHub
追加ライブラリ無しで正規表現が書けました。

STLに慣れているとstd::sregex_iteratorが奇妙に見えますが、これで複数のOpenGL関数定義を巡回させます。std::regex_matchでも正規表現を実行できますが、こちらは最初の一回しかマッチさせられません。マッチ結果はstd::smatchを使って戻り値、関数名、引数リストを取り出します。

GitHubはここです。

No comments:

Post a Comment