前回、「次回はGlut_BCCを作る為に必要なGLUTの機能をクラス化した"CGLUT"クラス(CGLUT.h)を解説します」などと書きましたが、実は単に関数群をクラスメンバーにした程度で「本当に必要があるの?」程度のクラスです。

 

しかし、

 

コーディングの効率とかの効率とか隠蔽化とかの問題ではなく、「私の学習(『フゥーン、そうなんだー』)」効果は結構ありました。要すればGLUTのお作法に沿ってコンストラクターでオブジェクトを作り(従ってその際のパラメーターを内部にメンバーとして保有します)、関数群はほぼそのまま(従って全部は無理なのでアプリを書くのに必要なものだけにしました)、定番処理(視点設定や視野空間の設定等)を工夫した程度です。(デストラクターなどは全く手を入れてません。→ウィンドウ廃棄(glutDestroyWindow)程度は入れるべきだったかな?)

 

以下を観ればほとんどGLUTで書くのと変わりないように見えますが、最大の利点はワイアー、ソリッド各9,全18の基本図形を好きに呼び出せるところでしょうか?

 

次回からはSkeltonWizardで作成したBCCSkeltonのプログラムを解説しましょう。

 

【CGLUT.h】

////////////////////////////////////
// CGLUT.h for BCC Skelton
// GLUT(OpenGL)クラス定義ファイル
// Copyright (c) May, 2024
//        By Ysama
////////////////////////////////////

#include    <GL\freeglut.h>                //freeglutライブラリをWindowsで使う為
#pragma comment(lib, "freeglut.lib")

class CGLUT
{
private:
    //ウィンドウ関連メンバー
    HWND m_hWnd = NULL;                                //表示ウィンドウハンドル
    int m_win_no;                                    //ウィンドウ番号
    int m_x = 100;                                    //表示ウィンドウx位置
    int m_y = 100;                                    //表示ウィンドウy位置
    int m_w = 640;                                    //表示ウィンドウ幅
    int m_h = 480;                                    //表示ウィンドウ高さ
    unsigned int m_mode = GLUT_SINGLE | GLUT_RGBA;    //表示ウィンドウモード GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE)
    char m_title[MAX_PATH] = {0};                    //表示ウィンドウタイトル
public:
    //描画オブジェクト関連
    int m_Obj = 0;                                    //描画オブジェクト番号(0 - 8)
    bool m_sw = FALSE;                                //ワイアーか、ソリッドかのフラグ(Solid - TRUE, Wire - FALSE)
    //gluLookAt関数関連
    GLdouble m_LA[9] = {0.0, 0.0, 2.0,                //視点位置(GLdouble) eyex, eyey, eyez,
                        0.0, 0.0, 0.0,                //クリップ平面の中心点(GLdouble) centerx, centery, centerz,
                        0.0, 1.0, 0.0};                //アっプベクター(GLdouble) upx, upy, upz
    //投影法選択
    int m_proj = 0;                                    //初期値はgluPerspective関数
    //gluPerspective関数関連
    GLdouble m_fov = 90.0;                            //視野(Fiield of view)で単位は度
    GLdouble m_aspect = m_w / m_h;                    //縦横比(幅 / 高さ)
    GLdouble m_near = 1.0;                            //視点から近クリップ平面までの距離(正)
    GLdouble m_far = 20.0;                            //視点から遠クリップ平面までの距離(正)
    //glFrustum関数関連
    //注意:m_nearとm_farは共用
    GLdouble m_left = -1.0;                            //クリップ平面左座標
    GLdouble m_right = 1.0;                            //クリップ平面右座標
    GLdouble m_bottom = -1.0;                        //クリップ平面下座標
    GLdouble m_top = 1.0;                            //クリップ平面上座標
    //glOrtho関数関連(立方体の左右上下前後の中心を並行投影)
    //注意:m_left、m_right、m_bottomm_topは共用

    GLdouble m_front = 1.0;                            //手前クリップ平面座標
    GLdouble m_back = -1.0;                            //奥クリップ平面座標
public:
    CGLUT();                                        //コンストラクター
    ~CGLUT();                                        //デストラクター
    HWND GethWnd() {return m_hWnd;}
    void SetPos(int x, int y) {m_x = x; m_y = y;}
    void SetSize(int w, int h) {m_w = w; m_h = h;}
    void SetTitle(char* name) {lstrcpy(m_title, name);}
    void SetMode(unsigned int mode) {m_mode = mode;}
    void Enable(GLenum cap) {glEnable(cap);}
    void Disable(GLenum cap) {glDisable(cap);}
    int Create(char*);
    void Display(void(*func)()) {glutDisplayFunc(func);} 
    void ReDisp() {glutPostRedisplay();}
    void SetLA(GLdouble, GLdouble, GLdouble,        //glLookAtと同じ
                GLdouble, GLdouble , GLdouble,        //値をm_LA配列に保存し、
                GLdouble, GLdouble, GLdouble);        //LookAt(gluLookAt)を呼ぶ
    void LookAt();
    void Color(GLint r, GLint g, GLint b, GLint a = 1) {glColor4i(r, g, b, a);}                        //オーバーロード(整数引数)
    void Color(GLfloat r, GLfloat g, GLfloat b, GLfloat a = 1.0) {glColor4f(r, g, b, a);}            //オーバーロード(単精度引数)
    void Color(GLdouble r, GLdouble g, GLdouble b, GLdouble a = 1.0) {glColor4d(r, g, b, a);}        //オーバーロード(倍精度引数)
    void Clear(GLbitfield mask) {glClear(mask);}    //GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_ACCUM_BUFFER_BIT, GL_STENCIL_BUFFER_BIT
    void ClearCol(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {glClearColor(red, green, blue, alpha);}
    void Transfer(GLdouble x, GLdouble y, GLdouble z) {glTranslated(x, y, z);}
    void Rotate(GLfloat angle, GLfloat x, GLfloat y, GLfloat z) {glRotatef(angle, x, y, z);}        //オーバーロード(単精度引数)
    void Rotate(GLdouble angle, GLdouble x, GLdouble y, GLdouble z) {glRotated(angle, x, y, z);}    //オーバーロード(倍精度引数)
    void Scale(GLfloat x, GLfloat y, GLfloat z) {glScalef(x, y, z);}                                //オーバーロード(単精度引数)
    void Scale(GLdouble x, GLdouble y, GLdouble z) {glScaled(x, y, z);}                                //オーバーロード(倍精度引数)
    void Reshape(void(*func)(int, int)) {glutReshapeFunc(func);}
    void Resize(int, int);
    void Refresh();                                                                                    //オーバーロード(引数なし)
    void Idle(void(*func)()) {glutIdleFunc(func);}
    void Mouse(void(*func)(int button, int state, int x, int y)) {glutMouseFunc(func);} 
    void Keyboard(void(*func)(unsigned char key, int x, int y)) {glutKeyboardFunc(func);}
    void Loop() {glutMainLoop();}
    void DrawObject();        //3Dオブジェクト描画関数
};

//コンストラクター
CGLUT::CGLUT() {

    glutInit(&__argc, __argv);            //void glutInit(int* &argc, char** argv);
    glutInitWindowPosition(m_x, m_y);    //void glutInitWindowPosition(int x, int y);
    glutInitWindowSize(m_w, m_h);        //void glutInitWindowSize(intw, int h);
    glutInitDisplayMode(m_mode);        //void glutInitDisplayMode(unsigned int mode);
}

//デストラクター
CGLUT::~CGLUT() {

}

//表示ウィンドウ生成
int CGLUT::Create(char* name = NULL) {

    m_win_no = glutCreateWindow("");    //int glutCreateWindow(char * title)    //戻り値はウィンドウ番号
    //GLのデバイスコンテキストハンドル取得
    HDC glDc = wglGetCurrentDC();
    //ウィンドウハンドル取得
    m_hWnd = WindowFromDC(glDc);
    if(!name)
        if(!m_title)
            SendMessage(m_hWnd, WM_SETTEXT, NULL, (LPARAM)__argv[0]);
        else
            SendMessage(m_hWnd, WM_SETTEXT, NULL, (LPARAM)m_title);
    else {
        lstrcpy(m_title, name);
        SendMessage(m_hWnd, WM_SETTEXT, NULL, (LPARAM)m_title);
    }
}

void CGLUT::SetLA(GLdouble eye_x, GLdouble eye_y, GLdouble eye_z,
                    GLdouble center_x, GLdouble center_y, GLdouble center_z,
                    GLdouble up_x, GLdouble up_y, GLdouble up_z) {
    m_LA[0] = eye_x; m_LA[1] = eye_y; m_LA[2] = eye_z;
    m_LA[3] = center_x; m_LA[4] = center_y; m_LA[5] = center_z;
    m_LA[6] = up_x; m_LA[7] = up_y; m_LA[8] = up_z;
    LookAt();
}

void CGLUT::LookAt() {
    gluLookAt(m_LA[0], m_LA[1], m_LA[2],
            m_LA[3], m_LA[4], m_LA[5],
            m_LA[6], m_LA[7], m_LA[8]);
}

void CGLUT::Resize(int width, int height) {

    glViewport(0, 0, width, height);    //ウインドウ全体に表示
    glMatrixMode(GL_PROJECTION);        //投影変換モードへ
    glLoadIdentity();                    //投影変換の変換行列を単位行列で初期化
    switch(m_proj) {
    case 0:    //①透視投影法1
        gluPerspective(m_fov, m_aspect, m_near, m_far);    //視野角度、縦横比、近クリップ平面までの距離、遠クリップ平面までの距離
        LookAt();
        break;
    case 1:    //②透視投影法2
        glFrustum(m_left, m_right, m_bottom, m_top, m_near, m_far);    //クリップ平面座標(left, right, bottom, top)、近クリップ平面までの距離、遠クリップ平面までの距離
        LookAt();
        break;
    case 2:    //③正投影法(遠近法を含まない投影)
        glOrtho(m_left, m_right, m_bottom, m_top, m_front, m_back);    //m_left, m_right, m_bottom, m_top, m_front, m_backで囲まれる立方体を並行投影
        break;
    }
    glMatrixMode(GL_MODELVIEW);            //視野変換・モデリング変換モードへ
    glLoadIdentity();                    //視野変換・モデリング変換の変換行列を単位行列で初期化
}

void CGLUT::Refresh() {

    Resize(m_w, m_h);
}

//3Dオブジェクト描画関数
void CGLUT::DrawObject() {

    switch(m_Obj) {
    default:    //1 - 8以外は0となる
    case 0:        //ティーポット
        if(m_sw)
            glutSolidTeapot(0.5);
        else
            glutWireTeapot(0.5);
        break;
    case 1:        //Cube(立方体)
        if(m_sw)
            glutSolidCube(0.5);
        else
            glutWireCube(0.5);
        break;
    case 2:        //Sphere(球)
        if(m_sw)
            glutSolidSphere(0.5, 20, 20);
        else
            glutWireSphere(0.5, 20, 20);
        break;
    case 3:        //Cone(円錐)
        if(m_sw)
            glutSolidCone(0.5, 0.8, 20, 20);
        else
            glutWireCone(0.5, 0.8, 20, 20);
        break;
    case 4:        //Torus (ドーナッツ)
        if(m_sw)
            glutSolidTorus(0.1, 0.4, 20, 20);
        else
            glutWireTorus(0.1, 0.4, 20, 20);
        break;
    case 5:        //Tetrahedron(4面体)
        if(m_sw)
            glutSolidTetrahedron();
        else
            glutWireTetrahedron();
        break;
    case 6:        //Octahedron(8面体)
        if(m_sw)
            glutSolidOctahedron();
        else
            glutWireOctahedron();
        break;
    case 7:        //Dodecahedron(12面体)
        if(m_sw)
            glutSolidDodecahedron();
        else
            glutWireDodecahedron();
        break;
    case 8:        //Icosahedron(20面体)
        if(m_sw)
            glutSolidIcosahedron();
        else
            glutWireIcosahedron();
        break;
    }
}