2011年2月18日金曜日

OpenGLで文字列描画

OpenGLには、高レベルライブラリのGLUTにも、文字列描画関数は含まれていません。
(freeglutにはあるみたいですが。)

そこで、printfを実装することにしました。

#2011/2/20更新: windows以外の時glXGetProcAdressでglWindowPos2iのエントリポイント取得するようにした

基本的にはGLUTのglutBitmapCharacterのラッパー関数。

ダウンロードはこちらから
使い方等はreadme.txtを参考にどうぞ。

大雑把に言えばGLUTに実装されてるビットマップ文字出力関数のラッパー。

以下ソースコードです。

GLprintf.h
/* この関数はGL/glut.hに含まれる、glutBitmapCharacter()関数のラップ関数です */

/* エスケープシーケンスはサポートしない。*/
/* 変換仕様は%d,%u,%o,%x,%s,%cのみサポート。 */
/* 1バイト文字のみ使用可 */

/* 作成するに当たってUNIXv7のソースコードを参考にした */

#include<stdarg.h>

int GLprintf(int x, int y, void *font, const char* format, ...);
void GLprintn(long num, int base, void *font);

GLprintf.c
#include"include/GLprintf.h"

#if defined (UNIX)
# define GL_GLEXT_PROTOTYPES
#endif

#if defined (__APPLE__)
# include <GLEW/glew.h>
#else
# include<GL/glew.h>
#endif

#if defined(_WIN32)
# include<GL/wglew.h>
 typedef void (WINAPI *WINPOS)(int x, int y);
#else
# include<GL/glxew.h>
#endif

#if defined (__APPLE__)
# include <GLUT/glut.h>
#else
# include<GL/glut.h>
#endif

#include<stdio.h>

int GLprintf(int x, int y, void *font, const char* format, ...)
{
 int count = 0;
 char *ptr, *str;
 char c;
 
 va_list list;

#if defined(_WIN32)
 WINPOS glWindowPos2i;
 glWindowPos2i = (WINPOS)wglGetProcAddress("glWindowPos2i");
#else
 PFNGLWINDOWPOS2IPROC glWindowPos2i;
 glWindowPos2i = (PFNGLWINDOWPOS2IPROC)glXGetProcAddress("glWindowPos2i");
#endif

 ptr = (char *)format;

 glWindowPos2i(x, y);
 va_start(list, format);

 while(*ptr)
 {
  if (*ptr != '%') { glutBitmapCharacter(font, *ptr++); ++count; }
  else
  {
   ++ptr;
   switch (*ptr) {
   case 's':
    ++ptr;
    str = va_arg(list, char *);
    while(*str) { glutBitmapCharacter(font, *str++); ++count; }
    break;
   case 'c':
    ++ptr;
    c = va_arg(list, char);
    glutBitmapCharacter(font, c);
    ++count;
    break;
   case 'd':
    ++ptr;
    GLprintn(va_arg(list, long), 10, font);
    ++count;
    break;
   case 'u':
    ++ptr;
    GLprintn(va_arg(list, long), 10, font);
    ++count;
    break;
   case 'o':
    ++ptr;
    GLprintn(va_arg(list, long), 8, font);
    ++count;
    break;
   case 'x':
    ++ptr;
    GLprintn(va_arg(list, long), 16,font);
    ++count;
    break;
   case '%':
    ++ptr;
    glutBitmapCharacter(font, '%');
    ++count;
    break;
   default:
    ++ptr;
    break;
   }
  }
 }

 va_end(list);
 return count;
}

void GLprintn(long num, int base, void *font)
{
 long a;

 if (num < 0) {
  glutBitmapCharacter(font, '-');
  num = -num;
 }

 if (a = num / base)
  GLprintn(a, base, font);
 glutBitmapCharacter(font, "0123456789ABCDEF"[(int)(num % base)]);

 return;
}