トップページ > 空即是色 > 2007年の記事 > MacOSX環境のOpenGLで日本語文字列の描画
空即是色 MacOSX環境のOpenGLで日本語文字列の描画
2007年 10月07日

Cocoaを利用することで、意外と簡単にできる。
大きな流れとしては、
- NSFontに日本語フォント(例えばヒラギノ)を設定する。
- NSAttributedStringを↑のNSFontで作成。
- NSImageに文字を描画。
- それを、ビットマップ画像(NSBitmapImageRep)に変換する。
- んで、OpenGLのテクスチャに登録して描画
日本語文字列を簡単に描画できるGLTexStringクラスを作ったので、詳しくは下記を参照。
- 2007年10月8日追記
- メモリ管理が適当だったので、その辺を修正しました。
- /Developer/Examples/OpenGL/Cocoa/GLImageWall/に、stringTextureというより汎用的に使用できるクラスがあります(via hrkw氏)。
GLTexStringの使い方
GLTexString *texStr;
- (void)initGL {
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClearDepth( 1.0f );
glDisable(GL_CULL_FACE);
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
NSString *string = [NSString stringWithCString:"こんにちは、世界!"];
texStr = [[GLTexString alloc] initWithString:string];
}
- (void)loop {
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt( 0, 0, 8, 0, 0, 0, 0, 1, 0 );
glPushMatrix();
glTranslatef( -4.5, -0.5, 0 );
glColor3f( 1, 1, 1 );
[texStr draw];
glPopMatrix();
[[self openGLContext] flushBuffer];
}
GLTexString.h
#import <Cocoa/Cocoa.h>
#import <OpenGL/gl.h>
#import <OpenGL/OpenGL.h>
#define TEX_WIDTH 128
#define TEX_HEIGHT 128
#define FONT_NAME @"HiraKakuPro-W6"
/*
* HiraKakuPro-W3
* HiraKakuPro-W6
* HiraKakuStd-W8
* HiraMaruPro-W4
* HiraMinPro-W3
* HiraMinPro-W6
*/
@interface GLTexString : NSObject
{
NSString *string;
NSAttributedString *attrString;
GLuint *texId;
}
- (id) initWithString:(NSString*)aString;
- (void) draw;
- (void) dealloc;
@end
GLTexString.m
#import "GLTexString.h"
@implementation GLTexString
- (id) initWithString:(NSString*)aString {
[super init];
int i, strSize;
float fontSize;
NSFont *font;
NSDictionary *attrsDictionary;
NSAttributedString *singleChar;
NSImage **images;
NSBitmapImageRep **imageReps;
NSImage* img;
NSPoint point;
NSSize size, screenResolution;
// copy to string from aString
string = [NSString stringWithString:aString];
// alloc texture id and image buffer
strSize = [string length];
texId = (GLuint*)malloc( sizeof(GLuint)*strSize );
images = (NSImage**)malloc( sizeof(NSImage*)*strSize );
imageReps = (NSBitmapImageRep**)malloc( sizeof(NSBitmapImageRep*)*strSize );
for( i = 0; i < strSize; i++ ){
images[i] = [[NSImage alloc] initWithSize:NSMakeSize( TEX_WIDTH, TEX_HEIGHT )];
}
// font settings
screenResolution = [[[[NSScreen mainScreen] deviceDescription] objectForKey:NSDeviceResolution] sizeValue];
fontSize = TEX_WIDTH * 72.0/screenResolution.width;
font = [NSFont fontWithName:FONT_NAME size:fontSize];
attrsDictionary = [NSDictionary dictionaryWithObjectsAndKeys:
font, NSFontAttributeName,
[NSColor whiteColor], NSForegroundColorAttributeName,
[NSColor clearColor], NSBackgroundColorAttributeName,
nil
];
// alloc attributed string
attrString = [[NSAttributedString alloc] initWithString:string attributes:attrsDictionary];
// create texture id
glEnable( GL_TEXTURE_2D );
glGenTextures( strSize, texId );
// build texture image
for( i = 0; i < strSize; i++ ){
img = images[i];
singleChar = [attrString attributedSubstringFromRange:NSMakeRange(i,1)];
// setting background color
[img setBackgroundColor:[NSColor clearColor]];
// calc center position
size = [singleChar size];
point = NSMakePoint( (TEX_WIDTH-size.width)/2, (TEX_HEIGHT-size.height)/2 );
// draw character to image
[img lockFocus];
[singleChar drawAtPoint:point];
[img unlockFocus];
// alloc bitmap image from NSImage
imageReps[i] = [[NSBitmapImageRep alloc] initWithData:[img TIFFRepresentation]];
// texture settings
glBindTexture( GL_TEXTURE_2D, texId[i] );
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA,
TEX_WIDTH, TEX_HEIGHT, 0,
[imageReps[i] hasAlpha] ? GL_RGBA :GL_RGB,
GL_UNSIGNED_BYTE,
[imageReps[i] bitmapData]
);
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glBindTexture( GL_TEXTURE_2D, 0 );
}
glDisable( GL_TEXTURE_2D );
// release
for( i = 0; i < strSize; i++ ){
[imageReps[i] release];
[images[i] release];
}
free( imageReps );
free( images );
return self;
}
- (void) draw {
int i, strSize;
strSize = [string length];
glEnable( GL_TEXTURE_2D );
for( i = 0; i < strSize; i++ ){
glBindTexture( GL_TEXTURE_2D, texId[i] );
glBegin(GL_POLYGON);
glTexCoord2f( 0, 1 );
glVertex3f( i*1, 0, 0 );
glTexCoord2f( 1, 1 );
glVertex3f( i*1+1, 0, 0 );
glTexCoord2f( 1, 0 );
glVertex3f( i*1+1, 1, 0 );
glTexCoord2f( 0, 0 );
glVertex3f( i*1, 1, 0 );
glEnd();
}
glDisable( GL_TEXTURE_2D );
}
- (void) dealloc {
glDeleteTextures( [string length], texId );
free( texId );
[attrString release];
[super dealloc];
}
@end
トラックバック
この記事のトラックバックURL:http://null-null.net/mt/mt-tb.cgi/488
コメント
hrkw (2007年10月07日)
/Developer/Examples/OpenGL/Cocoa/GLImageWall/
にstringTextureってクラスが入ってて、そいつは結構よくできてますよ。
ちょうど某展で日本語やってくれって言われて使ったところでした。
でもって、このサンプル自体かなり用途限定なので、ぜひマルチモニタで見てやってください。
nogami (2007年10月08日)
おー勉強になります。
GL_TEXTURE_RECTANGLE_EXTを使うと、
2の累乗以外のサイズもテクスチャに設定できるとは。
今回は一文字ごとにテクスチャにして操作したいので、
stringTextureはそれ以外の所で使ってみようと思います。
>ぜひマルチモニタで見てやってください。
見てみたものの、マルチモニタ環境ではないので用途は謎でした…orz
さ (2007年10月08日)
色々やってみた感じQuesoGLC(なぜか発音できない)が一番楽だったよー
依存ライブラリが2つぐらいあるけど、UTF-8エンコードのconst char*を渡すと勝手に書いてくれます。
http://quesoglc.sourceforge.net/
nogami (2007年10月09日)
おーこれは、MacOSX環境に限らずマルチプラットフォーム使えるのかな。
試しにmake installして、適当なサンプルをコンパイルしてみたら、いろいろエラーが…
これは使うまでがハードル高いかも。

