質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.52%

  • OpenGL

    167questions

    OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。

openGLで描画したい 色を変えたり、消したり

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 216

0126tami

score 4

 前提・実現したいこと

前回もここでまったくわからないopenGLについて質問させていただいたのですが、また質問させていただきたいと思います。

openGLでの描画がしたいと思っていてペイントソフトのように作るとこまでは前の質問にて解決しました。
次は画面上にボタンを作ってそのボタンを押すとペンの色が変わるというものとまた違うボタンを押すと一度描画した線が消えるというものを作りたいです。

ボタンだと難しいようでしたらあらかじめキーボード入力を決めておいて Bを入力したら 青色のペイント Yを入力したら 一度描画した線が消えるものです。

自分のような無知が質問するのも申し訳ないのですがどうしても作りたいので、協力してくださると助かります!!
よろしくお願いいたします

 ソースコード

int WINW = 600;
int WINH = 400;
const int TEXTMAX = 40;
const int POINTMAX = 10000; // 大量の角を持つ折れ線を描いているのだから、バッファサイズが10点分しかないと線がすぐ消えていってしまう
char text[TEXTMAX];
double xList[POINTMAX];
double yList[POINTMAX];
int textnum;
int pointnum;

void DrawString() {
glRasterPos3d(0, 0, 0);//0,0,0位置をスタート位置にする

glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'P');
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'a');
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'i');
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 'n');
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, 't');
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, '!');
}

void myDisplay() {
int i, j;

glClearColor(1.0, 1.0, 1.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);

DrawString();

glColor3d(1.0, 0.0, 0.0);
glBegin(GL_LINE_STRIP);
for (i = 0; i < POINTMAX; i++) {
j = (pointnum + i) % POINTMAX;
if (xList[j] == -20.0) {
// 座標バッファに目印となる値が見つかったら、そこをラインストリップの区切りとする
glEnd();
glBegin(GL_LINE_STRIP);
} else if (xList[j] >= -1.0 && yList[j] >= -1.0) {
glVertex2d(xList[j], yList[j]);
}
}
glEnd();

glRasterPos2d(-0.9, -0.7);

glutSwapBuffers();
}

void myKeyboard(unsigned char key, int x, int y) {
if (key == 0x1B) exit(0);
text[textnum] = key;
textnum = (textnum + 1) % TEXTMAX;
glutPostRedisplay();
}

void myMouseFunc(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
// マウスボタンが放されたら、目印となる適当な値を座標バッファに入れてやる
// myDisplay中でその値が見つかったら、そこでラインストリップを区切ってやる
xList[pointnum] = -20.0;
yList[pointnum] = 0.0;
pointnum = (pointnum + 1) % POINTMAX;
glutPostRedisplay();
}
}

void myMotionFunc(int x, int y) {
// 前回のマウス座標と相違があれば、変更前のmyMouseFuncの
// ifブロック内でやっていたのと同じことを行う
static int prevX = -10.0, prevY = -10.0;
if (x == prevX && y == prevY) return;
prevX = x;
prevY = y;
xList[pointnum] = (((double)x / WINW) * 2) - 1;
yList[pointnum] = ((((double)y / WINH) * 2) - 1)*(-1);
pointnum = (pointnum + 1) % POINTMAX;
glutPostRedisplay();
}

void myReshape(int width, int height) {
glViewport(0, 0, width, height);
WINW = width;
WINH = height;
}

void myInit(char* progname) {
int i;
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
glutInitWindowSize(WINW, WINH);
glutInitWindowPosition(0, 0);
glutCreateWindow(progname);
pointnum = 0;
for (i = 0; i < POINTMAX; i++) {
xList[i] = -10.0;
yList[i] = -10.0;
}
textnum = 0;
for (i = 0; i < TEXTMAX; i++) {
text[i] = '?0';
}
}

int main(int argc, char* argv[]) {
glutInit(&argc, argv);
myInit(argv[0]);
glutKeyboardFunc(myKeyboard);
glutMouseFunc(myMouseFunc);
glutMotionFunc(myMotionFunc); // モーションイベント用のハンドラーを登録
glutReshapeFunc(myReshape);
glutDisplayFunc(myDisplay);
glutMainLoop();
return 0;
}

 試したこと

ここに問題に対して試したことを記載してください。

 補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

0

GLUT自体にはUIを簡単に描画できる機能は付属していないようなので、ひとまずキーボード操作で色変更機能と描画クリア機能を作ってみるのがいいかと思います。

描いた線を消すのは、myInit内で初期化した時と同じようにxListyListの中身を全部(-10.0, -10.0)にリセットしてしまえばいいでしょう。
色変えについては、正直自分でもちょっと妙なやり方だとは思うのですが...

  • 新たな目印値-30.0を導入し、描画時、座標バッファ中にこの目印が現れたら色変えを行う。
  • 変えるべき色は座標バッファのy成分、およびその次の座標のx成分とy成分に埋め込む。

といった方法を試してみました。
下記のようにmyDisplaymyKeyboardに変更を加え、色情報埋め込み用関数setColorを追加しました。

void myDisplay() {
    int i, j;

    glClearColor(1.0, 1.0, 1.0, 0.0);
    glClear(GL_COLOR_BUFFER_BIT);

    glColor3d(1.0, 0.0, 0.0); // 最初のglColor3dをDrawStringより手前に移動
    DrawString();

    glBegin(GL_LINE_STRIP);
    for (i = 0; i < POINTMAX; i++) {
        j = (pointnum + i) % POINTMAX;
        if (xList[j] == -20.0) {
            // 座標バッファに目印となる値が見つかったら、そこをラインストリップの区切りとする
            glEnd();
            glBegin(GL_LINE_STRIP);
        } else if (xList[j] == -30.0) {
            // 色変更の目印が見つかったら、そこに埋め込まれた色情報を取り出してglColor3dに渡す
            double red = yList[j];
            i++;
            j = (pointnum + i) % POINTMAX;
            double green = xList[j];
            double blue = yList[j];
            glColor3d(red, green, blue);
        } else if (xList[j] >= -1.0 && yList[j] >= -1.0) {
            glVertex2d(xList[j], yList[j]);
        }
    }
    glEnd();

    glRasterPos2d(-0.9, -0.7);

    glutSwapBuffers();
}

void setColor(double red, double green, double blue) {
    // 座標バッファに色変更の目印、および色情報を埋め込む
    xList[pointnum] = -30.0; // 目印の値
    yList[pointnum] = red; // 赤
    pointnum = (pointnum + 1) % POINTMAX;
    xList[pointnum] = green; // 緑
    yList[pointnum] = blue; // 青
    pointnum = (pointnum + 1) % POINTMAX;
}

void myKeyboard(unsigned char key, int x, int y) {
    if (key == 0x1B) exit(0);
    if (key == 'r') {
        // Rキー押下...赤色に変更
        setColor(1.0, 0.0, 0.0);
    } else if (key == 'g') {
        // Gキー押下...緑色に変更
        setColor(0.0, 1.0, 0.0);
    } else if (key == 'b') {
        // Bキー押下...青色に変更
        setColor(0.0, 0.0, 1.0);
    } else if (key == 'y') {
        // Yキー押下...座標バッファの内容全体を初期値(-10.0, -10.0)に戻す
        for (int i = 0; i < POINTMAX; i++) {
            xList[i] = -10.0;
            yList[i] = -10.0;
        }
    } else {
        text[textnum] = key;
        textnum = (textnum + 1) % TEXTMAX;
    }
    glutPostRedisplay();
}

本来なら座標だけを格納するべきxListyListをどんどん引っかき回してしまい申し訳ないです...
この先もっとプログラムを機能拡張していくつもりでしたら、そろそろ設計見直しの頃合いかもしれません。

あいにく私はCやC++の経験が足りず具体的なアドバイスができないのですが、一例としてはオブジェクト指向的に「文字列オブジェクト...文字列、文字の色、描画座標を持つ」「フリーハンド曲線オブジェクト...曲線の色、頂点座標のリストを持つ」...といった感じに図形を設計しておいて、myDisplay内では画面内のこれらオブジェクトの描画メソッドを順次実行していく、なんていうのはどうでしょう?

※今回はキーボード入力で各機能を実行する方式にしましたが、GLUT向けのUIキットとしてGLUI(GLUI User Interface Library, v1GitHub - libglui/glui: GLUI is a GLUT-based C++ user interface library which provides controls such as buttons, checkboxes, radio buttons, and spinners to OpenGL applications. It is window-system independent, using GLUT or FreeGLUT.)といったものがあるようです。
検索してみただけで試してはおりませんが、ボタンなどの他にも3Dオブジェクトの移動や回転のためのコントロールも用意されているようですので、なかなか便利そうです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/07/19 11:13

    回答ありがとうございます!
    思ったとおりのものができてよかったです

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • OpenGL

    167questions

    OpenGLは、プラットフォームから独立した、デスクトップやワークステーション、モバイルサービスで使用可能な映像処理用のAPIです。