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

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

ただいまの
回答率

88.59%

C++ openGL BMP描画について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,085

nia_1001

score 13

前提・実現したいこと

24BitのBMP描画はできました...

しかしRGBの配置が変なので変更したのですが色が白黒になってしまいます

配列を変える前はこの画像は青のキャラではなくオレンジで描画されてました

これを下の画像のように正しい色で描画したいです

あと画像が反転してるのでそれも直したいです

イメージ説明

発生している問題・エラーメッセージ

エラーメッセージ

該当のソースコード

#include <stdio.h>
#include <Windows.h>
#include "glut.h"
#include "Tex.h"


int TexFromBMP(const char * _fileName)
{
    FILE *pFile;
    fopen_s(&pFile, _fileName, "rb");//ファイルの読み込み

    if (pFile == nullptr)
    {
        printf("%s open failed\n", _fileName);
        return 1;
    }
    printf("%s open\n", _fileName);

    BITMAPFILEHEADER bf;//ヘッダーのデータを格納する

    fread(&bf, sizeof BITMAPFILEHEADER, 1, pFile);
    printf("bf size:%d\n", bf.bfSize);//ファイルサイズ

    BITMAPINFOHEADER bi;
    fread(&bi, sizeof BITMAPINFOHEADER, 1, pFile);

    printf("biWidth:%d biHHeight:%d\n", bi.biWidth, bi.biHeight);
    printf("biBitCount:%d\n",bi.biBitCount);

    typedef struct {
        unsigned char r, g, b;//24Bitなので
    }RGB;
    RGB *bits = (RGB*)malloc(sizeof RGB * bi.biWidth * bi.biHeight);//ピクセルデータを確保する
    fread(bits, sizeof RGB, bi.biWidth * bi.biHeight, pFile);//ピクセルデータを読み込んだ


    //RGBのRとBを入れ替えた
    for(int y=0; y<bi.biHeight; y++)
        for (int x = 0; x < bi.biWidth; x++)
        {
            RGB *pBit = &bits[y * bi.biWidth + x];
            unsigned char temp = pBit->r;
            pBit->r = pBit->b;
            pBit->b = temp;

        }
    /*for (int y = 0; y < bi.biHeight; y++)
        for (int x = 0; x < bi.biWidth; x++)
        {
            RGB *pBit0 = &bits[y*bi.biWidth+x];
            RGB *pBit1 = &bits[(bi.biHeight - 1 - y)*bi.biWidth + x];
            RGB temp = *pBit0;
            *pBit0 = *pBit1;
            *pBit1 = temp;
        }*/

    //2次元テクスチャを描画
    glTexImage2D(
        GL_TEXTURE_2D,    //GLenum target,
        0,//GLint level,
        GL_RGB,    //GLint internalformat,
        bi.biWidth,        //GLsizei width,
        bi.biHeight,    //GLsizei height, 
        0,//GLint border,
        GL_RGB,//GLenum format,
        GL_UNSIGNED_BYTE,//GLenum type, 
        bits);//const GLvoid *pixels

    //フィルタリング
    glTexParameteri(
        GL_TEXTURE_2D,//GLenum target,
        GL_TEXTURE_MAG_FILTER,//GLenum pname,
        GL_NEAREST//GLint param
    );
    glTexParameteri(
        GL_TEXTURE_2D,//GLenum target,
        GL_TEXTURE_MIN_FILTER,//GLenum pname,
        GL_NEAREST//GLint param
    );
    free(bits);
    fclose(pFile);

    return 0;
}

C++ main

#include <stdio.h>
#include <time.h>
#include "Font.h"
#include "glm/glm.hpp"
#include "glut.h"
#include "Rect.h"
#include "Ball.h"
#include "Tex.h"

using namespace glm;

#define BALL_MAX 256

ivec2 WindowSize = { 600,420 }; //Windowのサイズ 縦,横

bool Keys[256];//押されているかのフラグ

Ball balls[BALL_MAX];

Rect rect1 = Rect(vec2(100, 100), vec2(100, 200));
Rect rect2 = Rect(vec2(WindowSize.x/2, WindowSize.y/2), vec2(200, 100));


void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT); //GLbitfield mask 画面の情報をリセット

    //2D
    glMatrixMode(GL_PROJECTION);//GLenum mode

    glLoadIdentity();
    gluOrtho2D(
        0,//GLdouble left,
        WindowSize.x,//GLdouble right,
        WindowSize.y,//GLdouble bottom,
        0//GLdouble top

    );
    glMatrixMode(GL_MODELVIEW); //GLenum mode モード設定
    glLoadIdentity();//リセットしている

    /*if (rect1.Intersect(rect2))
        glColor3ub(0xff, 0x00, 0x00);
    else
        glColor3ub(0x00, 0x00, 0xff);
    rect1.Draw();

    glColor3ub(0x00, 0xff, 0x00);
    rect2.Draw();*/

    //unsigned char pixels[] = {
    //    0xff,0x00,0x00,//赤
    //    0x00,0xff,0x00,//緑
    //    0x00,0x00,0xff,//青
    //    0xff,0xff,0x00//黄
    //}; 
    //glPixelStorei(
    //    GL_UNPACK_ALIGNMENT,//GLenum pname
    //    1//GLint param
    //);

    glEnable(GL_TEXTURE_2D);//2次元テクスチャを有効

    Rect(vec2(0,0),vec2(150,150)).Draw();

    //*for (int i = 0; i < BALL_MAX; i++)
    //{
    //    balls[1].Draw();
    //}
    //float y=0;*/
    FontBegin();
    /*FontSetPosition(0, y);*/
    //FontDraw("min:%f max:%f", FontGetWeightMin(), FontGetWeightMax());


    FontEnd();

    glutSwapBuffers();//命令

}

void Idle(void)
{
    float f = 0.5;
    if (Keys['w'])rect1.m_position.y -= f;
    if (Keys['s'])rect1.m_position.y += f;
    if (Keys['a'])rect1.m_position.x -= f;
    if (Keys['d'])rect1.m_position.x += f;
    for (int i = 0; i < BALL_MAX; i++)
    {

        balls[i].Update();
        //跳ね返り
        if (balls[i].m_position.x >= WindowSize.x)//右壁
        {
            balls[i].m_position = balls[i].m_LastPosition;
            balls[i].m_speed.x = -fabs(balls[i].m_speed.x);
        }
        if (balls[i].m_position.x < 0)//左壁
        {
            balls[i].m_position = balls[i].m_LastPosition;
            balls[i].m_speed.x = fabs(balls[i].m_speed.x);
        }
        if (balls[i].m_position.y < 0)//上壁
        {
            balls[i].m_position = balls[i].m_LastPosition;
            balls[i].m_speed.y = fabs(balls[i].m_speed.y);
        }
        if (balls[i].m_position.y >= WindowSize.y)//下壁
        {
            balls[i].m_position = balls[i].m_LastPosition;
            balls[i].m_speed.y = -fabs(balls[i].m_speed.y);
        }
    }

    glutPostRedisplay();
}

//再描画命令
void Timer(int value)
{
    glutPostRedisplay();//再度描画命令
    glutTimerFunc(
        1000/60,//unsigned int millis 〇秒後に開始 60FPSにしてる
        Timer,//void (GLUTCALLBACK *func)(int value) 関数起動
        0); //int value 渡す数値 必要ないので0

}
void Reshape(int width, int height)
{
    printf("reshape: width:%d height:%d\n", width, height);//確認のため
    //更新するのでwindowサイズが変わっても大丈夫
    glViewport(
        0, 0,//(GLint x,y, 座標
        width, height//GLsizei width,height) 幅高さ
    );
    //windowサイズ更新
    WindowSize = ivec2(width, height);
}
void (Keyboard)(unsigned char key, int x, int y)//intはマウス
{
    if (key == 0x1b)
    {
        exit(0);
    }
    printf("Keyboard:\'%c\'(%#x)\n",key,key);
    Keys[key] = true;
}
void (KeyboardUp)(unsigned char key, int x, int y)
{
    printf("KeyboardUp:\'%c\'(%#x)\n", key, key);
    Keys[key] = false;
}

int main(int argc, char *argv[])
{
    srand(time(NULL));
    for (int i = 0; i < BALL_MAX; i++)
    {
    balls[i].m_speed = normalize( vec2((float)rand()/RAND_MAX, (float)rand()/RAND_MAX));

    }

    glutInit(
        &argc, //int *argcp,
        argv); //char **argv);
    glutInitDisplayMode(GL_DOUBLE);//unsigned int mode ダブルバッファを使うようにする
    glutInitWindowSize(WindowSize.x, WindowSize.y); //int width, int height
    glutCreateWindow("title");//const char *title

    TexFromBMP("Megaman01.bmp");

    glutDisplayFunc(display);//void (GLUTCALLBACK *func)(void)
    glutIdleFunc(Idle);//void (GLUTCALLBACK *func)(void) Idle状態のときに呼ばれる
    //垂直同期がとれないためTimerでやる
    glutTimerFunc(
        0,//unsigned int millis 〇秒後に開始
        Timer,//void (GLUTCALLBACK *func)(int value) 関数起動
        0); //int value 渡す数値 必要ないので0

    //windowのサイズが変わったときのコールバック関数定義
    glutReshapeFunc(Reshape);//void (GLUTCALLBACK *func)(int width, int height) 
    //Keyboardを取得
    glutKeyboardFunc(Keyboard);//void (GLUTCALLBACK *func)(unsigned char key, int x, int y)
    //keyrepeatを無効にする
    glutIgnoreKeyRepeat(GL_TRUE);//int ignore
    //keyboardが離されたときの処理
    glutKeyboardUpFunc(KeyboardUp);//void (GLUTCALLBACK *func)(unsigned char key, int x, int y)
    glutMainLoop();//MainLoop

}


```

試したこと

配列を変えた感じです

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

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

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

0

BMPファイルはRGBではなく、BGRの順で格納されています。
BRの並び順を入れ替えるのではなく、glTexImage2Dの引数でGL_RGBの代わりにGL_BGRを指定すればよいのでは?
glTexImage2D

あと画像が反転してるのでそれも直したいです

BITMAPINFOHEADERbiHeightが正の場合は下から上に向かって格納されています。
BITMAPINFOHEADER

biHeight
The height of the bitmap, in pixels. If biHeight is positive, the bitmap is a bottom-up DIB and its origin is the lower-left corner. If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner.

If biHeight is negative, indicating a top-down DIB, biCompression must be either BI_RGB or BI_BITFIELDS. Top-down DIBs cannot be compressed.

If biCompression is BI_JPEG or BI_PNG, the biHeight member specifies the height of the decompressed JPEG or PNG image file, respectively.

各ライン毎のバイト数が4の倍数に満たない場合は0パディングされます。
このコードで24bitBMPファイルを読むとRGBが3バイトなので、画像の幅が4の倍数でない場合はずれますね。

    typedef struct {
        unsigned char r, g, b;//24Bitなので
    }RGB;
    RGB *bits = (RGB*)malloc(sizeof RGB * bi.biWidth * bi.biHeight);//ピクセルデータを確保する
    fread(bits, sizeof RGB, bi.biWidth * bi.biHeight, pFile);//ピクセルデータを読み込んだ

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/19 09:15 編集

    glTexImage2Dの引数でGL_RGBの代わりにGL_BGRですか

    すみませんopenGLのver.は1.1なのでGL_BGRという引数はなかったですが解決できました
    ありがとうございます

    お聞きしたいことがあるのですがOpenGLのverって上げたほうがいいですか?
    関数や定義が変わるらしいので今から上げるとなると不安です

    もし上げる際に利点とかがあれば教えてくれませんか?

    キャンセル

0

2乗のpixselサイズじゃないと読み込みませんでした
ただそれだけです

openGLのverは1.1です

2,4,8,16,32,64,128,256じゃないと読み込まない感じでした

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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

関連した質問

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