
[code]

    #include <GL/glut.h>
    #include "imageio.h"
    
    // グローバル変数
    unsigned char dat[320 * 240 * 3];       /* 画像データ格納用の配列      */
    int cm;                             /* cm: 1(モノクロ), 3(カラー)  */
    int height, width;                  /* height: 高さ(y), width: 幅(x)*/
    // 画素の色成分を扱う構造体
    typedef struct pixelColor {
      unsigned char R;
      unsigned char G;
      unsigned char B;
    } pColor;
    
    // キャンバスに画素値（色）を描画する関数
    void draw_pixel(int x, int y, pColor c) {
      glColor3ub(c.R, c.G, c.B);            /* 指定色(pColor c)をセット　   */
      glBegin(GL_POINTS);
      glVertex2d(x, y);             /* セットした色をキャンバス     */
      glEnd();                          /* (x,y)座標に描画   　  　　   */
    }
    
    // キャンパスに画像を描画するコールバック関数
    void display(void) {
      int    x, y, n;                       /* (x,y): x-y 座標        */
      pColor color;
    
      glClear(GL_COLOR_BUFFER_BIT);
      for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
          switch(cm) {
            case 1:                     /* モノクロ画像の場合    */
              n = width * y + x;            /* (x,y)の輝度値を取得 */
              color.B = dat[n];
              color.G = dat[n];
              color.R = dat[n];
              draw_pixel(x, y, color);
              break;
            case 3:                     /* カラー画像の場合     */
              n = (width * y + x) * 3;      /* (x,y)のRGB値を取得    */
              color.B = dat[n];
              color.G = dat[n + 1];
              color.R = dat[n + 2];
              draw_pixel(x, y, color);
              break;
            default:
              printf("不正なカラーモードです.\n");
              exit(1);
          }
        }
      }
      glFlush();                            /* キャンバスを表示     */
    }
    
    // ウィンドウサイズ変更時に座標設定を行うコールバック関数
    void resize(int w, int h)
    {
      glViewport(0, 0, w, h);
      glLoadIdentity();
      glOrtho(0, w, 0, h, -1.0, 1.0);
    }
    
    // メイン関数
    int main(int argc, char** argv)
    {
    
      // BMP画像の読み込み
      if(argc < 2) {
        printf("画像ファイルを指定してください．\n");
        exit(1);
      }
      loadbmpfile(argv[1], &cm, &height, &width, dat);
      printf("file name: %s\n", argv[1]);
      printf("color_mode = %d\n", cm);
      printf("height = %d, width = %d\n", height, width);
    
      // GLUTによるウィンドウの初期化
      glutInit(&argc, argv);
      glutInitDisplayMode(GLUT_RGBA);
      glutInitWindowSize(width, height);
      glutInitWindowPosition(100, 100);
      glutCreateWindow(strcat("image viewer ", uid));
    
      // クリアカラー（背景）を黒にセット
      glClearColor(0.0, 0.0, 0.0, 1.0);
    
      // コールバック関数
      glutDisplayFunc(display);
      glutReshapeFunc(resize);
    
      //イベント処理ループ
      glutMainLoop();
    
      return 0;
    }
    
[/code]

imageio.h

[code]

    #include <stdio.h>
    #include <string.h>
    
    void loadbmpfile(char* loadfile, int* color_mode,
      int* height, int* width, unsigned char* dat)
    {
      FILE* fp;
      char fname[80];                       /* BMPファイル名         */
      unsigned char header[54]; /* ヘッダ格納用               */
      int wdth, hght, cm;               /* width, hight, color_mode */
      int pal[1024];                        /* カラーパレット格納用       */
      int pad, dm;                          /* パディングデータ格納用  */
      int j, k, l, m;                       /* ループ変数                */
    
      // BMPファイルのOpen処理
      strcpy(fname, loadfile);
      if (strstr(fname, ".bmp") == NULL)
        strcat(fname, ".bmp");
      fp = fopen(fname, "rb");
      if (fp == NULL)
      {
        printf("Can't find file: \"%s\".\n", loadfile);
        exit(-1);
      }
      // ヘッダ部の読み込み
      for (j = 0; j < 54; j++)
        header[j] = fgetc(fp);
      if (!(header[0] == 'B' && header[1] == 'M'))
      {
        printf("\"%s\" is not BMP file.\n", loadfile);
        exit(-1);
      }
      // 画像サイズ，カラーモードの取得
      wdth = header[18] + header[19] * 256; /* 画像の幅（width）  */
      hght = header[22] + header[23] * 256; /* 画像の高さ(height)    */
      cm = header[28] / 8;                                  /* cm=1:mono, 3:color   */
      // カラーパレットの読み込み
      if (cm == 1)
      {
        for (j = 0; j < 1024; j++)
          pal[j] = fgetc(fp);
      }
      // 画素データの読み込み
      pad = ((4 - (wdth % 4)) * cm) % 4; /* パディングデータのバイト数   */
      for (j = 0; j < hght; j++)
      { /* 画素データの取得         */
        for (k = 0; k < wdth; k++)
        {
          for (l = 0; l < cm; l++)
            *(dat++) = fgetc(fp);
        }
        for (m = 0; m < pad; m++)
          dm = fgetc(fp); /* パディングデータのスキップ  */
      }
      // BMPファイルのClose処理
      fclose(fp);
      // 画像サイズ，カラーモードをポインタ渡し
      *color_mode = cm;
      *height = hght;
      *width = wdth;
    }
    
[/code]


CC BY-SA 4.0
2023-10-23T15:41:11.670
96558
2023-10-25T02:56:32.243
2023-10-23T18:18:37.253
3060
60178
question
c opengl
次のプログラムを拡張して横に画像を二枚表示できるようにするにはどこに何を付け足したらいいでしょうか。


現コードには｛画像のデータと，それを参照して描画を行う処理｝が存在していてそれによって「画像１枚を表示する」を達成しているハズである．  
→ であれば，この｛画像データ，描画処理｝というペアを２組用意すれば「画像１枚を表示する ×２」を達成できるのではなかろうか．  
…というあたりからまずは検討してみれば良いのではないでしょうか．

## (1)画像のデータを増やす

画像のデータはこれですよね．

[code]

    unsigned char dat[320 * 240 * 3];
    int cm;
    int height, width;
    
[/code]

今は画像１枚分です．これを２枚分に増やせばよいわけです．  
方法はいくつか考えられるので好きな（というか「わかる」）方法でやると良いでしょう．  
以下に３つほど例を示しますが，他にも方法は考えられるでしょう．

[code]

    //例１：いかにも「コピペして増やしました」みたいな形．
    //苦労も多そうだが，
    //限られた知識のみで対処せねばならないような場面においては，
    //ある意味では最も分かりやすいとも言えなくもない…か？
    
      //１枚目の画像のデータ
    unsigned char dat[320 * 240 * 3];
    int cm;
    int height, width;
      //２枚目の画像のデータ（コピペして変数名末尾に '2' を付与しました）
    unsigned char dat2[320 * 240 * 3];
    int cm2;
    int height2, width2;
    
[/code]

[code]

    //例２：変数を全て配列に変更することで増やしてみました．
    //既存の変数の定義自体を変えているので，既存処理コードもそれに合わせて変更する必要があります．
    unsigned char dat[2][320 * 240 * 3];
    int cm[2];
    int height[2], width[2];
    
[/code]

[code]

    //例３：「画像１個分のデータ」という枠組みを用意し，それを２個作る形にしてみました．
    //もちろんこの場合も相応に既存処理コードを変更する必要があります．
    typedef struct ImageData  //画像１枚分のデータ
    {
      unsigned char dat[320 * 240 * 3];
      int cm;
      int height, width;
    } ImageData;
    
    ImageData Img[2];  //２つ用意した．
    
[/code]

## (2)処理を画像２枚分やる

画像の｛読込処理，描画処理｝も２枚分行うようにする必要がありますね．  
具体的な方法は，画像データを増やした方法次第となります．  
上記(1)で例2とか例3みたいな方法を採用している場合には，  
そもそもその時点で既に「処理の方はこうすればいいよね」というのが見えているハズなので，適切にやってください．

特に「こうすればいい」という考えが存在しない場合……  
最も頭を使わなくて良い方法は，上記(1)の例１のごとく「コードを丸ごとコピペして増やす」です．  
例えば描画処理で言えば，↓みたいな．

[code]

    void display(void) {
      int    x, y, n;
      pColor color;
      glClear(GL_COLOR_BUFFER_BIT);
    
      //１枚目の画像の描画処理
      for(y = 0; y < height; y++) {  //※ ここの height も(1)のやり方次第では適切に変える必要がある
        for(x = 0; x < width; x++) {  //※width についても同上．
          /* 長いので省略．「１枚目の画像」のデータを用いた処理． */
        }
      }
    
      //続いて２枚目の画像の描画処理をやるぜ！
      //↑の「１枚目～」のコードを丸ごとコピペしてきて，
      //「２枚目の画像」データを用いるように書き換えてやれば完成！
      for(y = 0; y < height; y++) {
        for(x = 0; x < width; x++) {
          /* 長いので省略．「２枚目の画像」のデータを用いた処理． */
        }
      }
    
      glFlush();
    }
    
[/code]

もちろんこのようなコピペプログラミングを無理矢理推したいわけではありません．  
が， **この質問をしているという状況から勝手に推測するに** ，  
【まずはコピペでも何でもいいのであまり形にこだわらずに「とりあえずは動く」形を作って→そこからコード改善に挑戦していく】  
という取り組み方も有りなのではないかな，とか思います．  
段階的に 復習/学習 していけるでしょうし，どの時点で「ここまでにするか」って止めても「動作としては達成しているコード」が手元にあるということになりますし．


CC BY-SA 4.0
2023-10-25T02:50:02.813
96577
2023-10-25T02:56:32.243
2023-10-25T02:56:32.243
52236
52236
96558
answer