1

私はビットマップ ローダーに取り組んできました。主な目標は、データを適切に解析して OpenGL でレンダリングすることだけです。x/y (つまり、ピクセル単位) でピクセルを描画する必要があるところです (少なくとも、レンダリングに関する限り、これは私が行う必要があると考えていることです)。既にテクスチャ オブジェクトをバインドして呼び出していglTexImage2D(...)ます。

現在、私が問題を抱えているのは、ピクセルごとのアルゴリズムです。

私が理解している限り、ビットマップ (別名 DIB) ファイルは、ピクセル配列と呼ばれるものにカラー データを格納します。ピクセルの各行はバイト数で構成され、各ピクセルは 4 (ピクセルあたり 32 ビット)、3 (ピクセルあたり 24 ビット)、2 (ピクセルあたり 16 ビット)、または 1 (ピクセルあたり 8 ビット) で割り切れるバイト数を保持します。ピクセル)。x

ピクセルをループしながら、同時にピクセル配列内の正しいオフセットを計算する必要があると思います。これは、ピクセルの x/y 座標に相対的です。しかし、これは本当ですか?そうでない場合は、どうすればよいですか?正直なところ、この質問で私に指示されたことを実行したにもかかわらず、このアプローチが正しいかどうかについて少し混乱しています。

ピクセルごとにそれを行うことが正しいアプローチであるglVertex*glTexCoord*思います.そもそも)。

また、私の質問には OpenGL 3.1 シェーダーが表示されていますが、SDL 1.2 に移行したため、適切なアルゴリズムが実装されるまで当面は即時モードを使用してから、最新の GL に戻すことができました。


私が解析しているテスト画像:

ビットマップ イメージ

これはデータ出力です (非常に長いためペーストビン化されています): http://pastebin.com/6RVhAVRq

そしてコード

void R_RenderTexture_PixByPix( texture_bmp_t* const data, const vec3 center )
{


    glBindTexture( GL_TEXTURE_2D, data->texbuf_id );

    glBegin( GL_POINTS );
    {
        const unsigned width  = data->img_data->width + ( unsigned int ) center[ VEC_X ];
        const unsigned height = data->img_data->height + ( unsigned int ) center[ VEC_Y ];

        const unsigned bytecount    = GetByteCount( data->img_data->bpp );

        const unsigned char* pixels = data->img_data->pixels;

        unsigned color_offset = 0;
        unsigned x_pixel;

        for ( x_pixel = center[ VEC_X ]; x_pixel < width; ++x_pixel )
        {
            unsigned y_pixel;

            for ( y_pixel = center[ VEC_Y ]; y_pixel < height; ++y_pixel )
            {

            }

            const bool do_color_update = true; //<--- replace true with a condition which checks to see if the color needs to be updated.

            if ( do_color_update )
            {
                glColor3fv( pixels + color_offset );
            }

            color_offset += bytecount;
        }
    }
    glEnd();

    glBindTexture( GL_TEXTURE_2D, 0 );
}
4

2 に答える 2

2

コードに OpenGL テクスチャのポイントが完全にありません。テクスチャは画像を保持し、ラスタライザーはピクセル データに対してすべての反復を行います。遅いピクセル プッシャー ループを自分で作成する必要はありません。

あなたのコードが今立っているように、そのテクスチャは完全に偽物であり、何もしません。glBindTexture の呼び出しを完全に省略しても機能しますが、実際には何も描画していないため、glColor の状態を設定するだけです。何かを描画するには、glVertex を呼び出す必要があります。

では、最新の GPU のピクセル プッシング パフォーマンスを活用して、実際にテクスチャを使用してみませんか? これはどう:

void R_RenderTexture_PixByPix( texture_bmp_t* const data, const vec3 center )
{
    if( 0 == data->texbuf_id ) {
        glGenTextures(1, &(data->texbuf_id));
        glBindTexture( GL_TEXTURE_2D, data->texbuf_id );

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
        // there are a few more, but the defaults are ok
        // if you didn't change them no need for further unpack settings

        GLenum internal_format;
        GLenum format;
        GLenum type;
        switch(data->img_data->bpp) {
        case 8:
            // this could be a palette or grayscale
            internal_format = GL_LUMINANCE8;
            format = GL_LUMINANCE;
            type = GL_UNSIGNED_BYTE;
            break;

        case 15:
            internal_format = GL_RGB5;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_SHORT_1_5_5_5;
            break;

        case 16:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_SHORT_5_6_5;
            break;

        case 24:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_BYTE;
            break;

        case 32:
            internal_format = GL_RGB8;
            format = GL_BGR; // BMP files have BGR pixel order
            type = GL_UNSIGNED_INT_8_8_8_8;
            break;

        }

        glTexImage2D( GL_TEXTURE_2D, 0, internal_format,
                      data->img_data->width, data->img_data->height, 0,
                      format, type, data->img_data->pixels );
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    } else {
        glBindTexture( GL_TEXTURE_2D, data->texbuf_id );
    }


    static GLfloat verts[] = {
            0, 0, 
            1, 0,
            1, 1,
            0, 1
    };    
    // the following is to address texture image pixel centers
    // tex coordinates 0 and 1 are not on pixel centers!
    float const s0 = 1. / (2.*tex_width);
    float const s1 = ( 2.*(tex_width-1) + 1.) / (2.*tex_width);
    float const t0 = 1. / (2.*tex_height);
    float const t1 = ( 2.*(tex_height-1) + 1.) / (2.*tex_height);
    GLfloat texcoords[] = {
            s0, t0,
            s1, t0,
            s1, t1,
            s0, t1
    };

    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    glEnable(GL_TEXTURE_2D);

    glVertexPointer(2, GL_FLOAT, 0, verts);
    glTexCoordPointer(2, GL_FLOAT, 0, texcoords);

    glColor4f(1., 1., 1., 1.);
    glDrawArrays(GL_QUADS, 0, 4);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_TEXTURE_COORD_ARRAY);

    glBindTexture( GL_TEXTURE_2D, 0 );
}
于 2013-01-15T11:27:26.923 に答える
1

あなたの直感は基本的に正しいです。ピクセルはバイトの配列として格納されますが、バイトは連続したグループに配置され、各グループは1つのピクセルを表します。単一のピクセルをアドレス指定するには、次のような計算を行う必要があります。

unsigned char* image_data = start_of_pixel_data;
unsigned char* pixel_addr = image_data + bytes_per_pixel * (y * width_in_pixels + x);

ピクセル単位の幅に注意してください。行の最後にパディングがあり、バイト単位の合計行幅を4/8/16/32/64などの倍数にすることがあります。何が起こっているのかを理解するために、最初に16進数のビットマップの実際のバイトを確認することをお勧めします。これは優れた学習演習であり、ピクセルウォーキングコードに高い信頼を与えることができます。これはあなたが望むものです。デバッガーを使用してこれを行うことができる場合があります。またはprintf、イメージバイトを超える単純なループを作成することもできます。

于 2013-01-15T06:38:25.517 に答える