The jonki

呼ばれて飛び出てじょじょじょじょーんき

【OpenGL】digitを表示してみた

こういうやつをOpenGLで書けないかやってみました。


ちなみにOpenGLはopenFrameworks上で直接叩いてます。y軸がOpenGLとは逆なので注意です。

JGraphics.h

メンバ関数ポインタとしてStickをtypedefしています。下図から分かるとおり6つのパーツ(これをスティックと呼びます)から数字は成り立っています。このスティックは横と縦のパーツからなりたっているので、それぞれ描画するdrawVStickとdrawHStickを与えます。

#ifndef JGRAPHICS_H_
#define JGRAPHiCS_H_

#include "ofMain.h"
#define DIGIT_PARTS_NUM 7

namespace jonki
{
class JGraphics
{

public:
	JGraphics(void);
	~JGraphics(void);

	//
	// (略)
	//

	void drawNumber(int num, float scale);
);

	typedef void (JGraphics::*Stick)();

private:
	void drawVStick();
	void drawHStick();

private:
	//
	// (略)
	//
	Stick sticks[DIGIT_PARTS_NUM];
	ofPoint moves[DIGIT_PARTS_NUM];
	unsigned char NUM_PAT[10];

};
}
#endif

JGraphics.cpp

まずsticksに上記図に対応するよう縦か横のdraw関数を与えます。次にこの数字の順番で記述するため、glTranslatef用の変数も用意します。最後(moves[6])は動く必要がないので、すべて0.fです。NUM_PATには0〜9の対応する数字のパターンを入れています。7個のスティックがtrueかfalseで書けるので下記のように書いています。あとはビット演算でiビット目(i本目)を書くかどうかを0x01と&演算子を取ることで分かります。

JGraphics::JGraphics(void)
{
	sticks[0] = &JGraphics::drawVStick;
	sticks[1] = &JGraphics::drawVStick;
	sticks[2] = &JGraphics::drawHStick;
	sticks[3] = &JGraphics::drawVStick;
	sticks[4] = &JGraphics::drawVStick;
	sticks[5] = &JGraphics::drawHStick;
	sticks[6] = &JGraphics::drawHStick;

	moves[0] = ofPoint(0.f, 4.f, 0.f);
	moves[1] = ofPoint(0.f, 4.f, 0.f);
	moves[2] = ofPoint(3.5f, -4.f, 0.f);
	moves[3] = ofPoint(0.f, -4.f, 0.f);;
	moves[4] = ofPoint(-3.5f, 0.f, 0.f);
	moves[5] = ofPoint(0.f, 4.f, 0.f);
	moves[6] = ofPoint(0.f, 0.f, 0.f);

	NUM_PAT[0] = 0x3f; //0011 1111, //!< 0
	NUM_PAT[1] = 0x18; //0001 1000, //!< 1
	NUM_PAT[2] = 0x76; //0111 0110, //!< 2
	NUM_PAT[3] = 0x7c; //0111 1100, //!< 3
	NUM_PAT[4] = 0x59; //0101 1001, //!< 4
	NUM_PAT[5] = 0x6d; //0110 1101, //!< 5
	NUM_PAT[6] = 0x6f; //0110 1111, //!< 6
	NUM_PAT[7] = 0x39; //0011 1001, //!< 7
	NUM_PAT[8] = 0x7f; //0111 1111, //!< 8
	NUM_PAT[9] = 0x7d; //0111 1101, //!< 9
}

//
// (略)
//

void JGraphics::drawNumber(int num, float scale)
{
	glPushMatrix();
		glScalef(scale, scale, 0.f);
		for(int i=0; i<DIGIT_PARTS_NUM; i++) {
			if((NUM_PAT[num] >> i) & 0x01) {
				(this->*sticks[i])();
			} 
			glTranslatef(moves[i].x, moves[i].y, moves[i].z);
		}
	glPopMatrix();
}

void JGraphics::drawVStick()
{
	glBegin(GL_POLYGON);
		glNormal3f(0.f, 0.f, 1.f);
		glVertex3f(0.5f, 0.f, 0.f);
		glVertex3f(0.f, 0.5f, 0.f);
		glVertex3f(0.f, 3.5f, 0.f);
		glVertex3f(0.5f, 4.f, 0.f);
		glVertex3f(1.f, 3.5f, 0.f);
		glVertex3f(1.f, 0.5f, 0.f);
	glEnd();
}


void JGraphics::drawHStick()
{
	glBegin(GL_POLYGON);
		glNormal3f(0.f, 0.f, 1.f);
		glVertex3f(0.5f, 0.f, 0.f);
		glVertex3f(1.f, 0.5f, 0.f);
		glVertex3f(3.5f, 0.5f, 0.f);
		glVertex3f(4.f, 0.f, 0.f);
		glVertex3f(3.5f, -0.5f, 0.f);
		glVertex3f(1.f, -0.5f, 0.f);
	glEnd();
}

あとはtestApp.cppとかで呼んであげればこの通り

//!< digit
glPushMatrix();
	for(int i=0; i<10; i++) {
		m_gfx.drawNumber(i, 30.f);
		glTranslatef(200, 0, 0);
	}
glPopMatrix();

いろいろやり方はあると思いますが、今回はちょっと変な方法で書いてみますた。とりあえずコンストラクタ内の設定値宣言が汚いですね、はい。

参考

メンバ関数ポインタについてはこちらを参照。
C++編(言語解説) 第34章 メンバ関数ポインタ

メンバ関数ポインタを経由してメンバ関数を呼び出すとき、->*演算子や .*演算子を使うことになります。