1

GL_arb_texture_rectanglelibpng 1.5を使用して、NPOTサイズのPNG画像をOpenGL ES 1.1のテクスチャとして使用しようとしています(そうではありません)。SDL を使用すると、NPOT 画像を NPOT テクスチャにブリットすることができましたが、libpng で同様のことを行う方法がわかりません。

元のテクスチャ (1280x720) を使用している場合、取得できるのは白い表面だけです。ファイル システムで 1024x512 にサイズ変更すると、問題なく表示されます。

何らかの理由で、NPOT テクスチャは 4.2 AVD で動作し-gpu onます。

これがコードです。直接 ing する代わりにlibzipを使用して APK から読み取るように変更されていますfopen

void png_zip_read(png_structp png, png_bytep data, png_size_t size)
{
    zip_file* file = static_cast<zip_file*>(png_get_io_ptr(png));
    zip_fread(file, data, size);
}

GLuint load_png_texture(const std::string& path, unsigned int& width,
                        unsigned int& height)
{
    if (!apk_path.length())
        throw "APK Path not set";

    zip* apk = zip_open(apk_path.c_str(), 0, NULL);
    if (!apk)
        throw "Error loading APK";

    zip_file* file = zip_fopen(apk, path.c_str(), 0);
    if (file == 0)
        throw path + ": " + strerror(errno);

    png_byte header[8];
    zip_fread(file, header, 8);
    if (png_sig_cmp(header, 0, 8)) {
        zip_fclose(file);
        zip_close(apk);
        throw path + " is not a PNG";
    }

    png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING,
                                             NULL, NULL, NULL);
    if (!png) {
        zip_fclose(file);
        zip_close(apk);
        throw "Failed to create png struct";
    }

    png_infop info = png_create_info_struct(png);
    if (!info) {
        png_destroy_read_struct(&png, (png_infopp) NULL, (png_infopp) NULL);
        zip_fclose(file);
        zip_close(apk);
        throw "Failed to create png info struct";
    }

    png_infop info_end = png_create_info_struct(png);
    if (!info_end) {
        png_destroy_read_struct(&png, &info, (png_infopp) NULL);
        zip_fclose(file);
        zip_close(apk);
        throw "Failed to create png info struct";
    }

    if (setjmp(png_jmpbuf(png))) {
        png_destroy_read_struct(&png, &info, &info_end);
        zip_fclose(file);
        zip_close(apk);
        throw "Error from libpng";
    }

    png_set_read_fn(png, file, png_zip_read);
    png_set_sig_bytes(png, 8);
    png_read_info(png, info);

    int bit_depth, color_type;
    unsigned int temp_width, temp_height;
    png_get_IHDR(png, info, &temp_width, &temp_height, &bit_depth,
                 &color_type, NULL, NULL, NULL);
    width = temp_width;
    height = temp_height;

    png_read_update_info(png, info);

    int row_bytes = png_get_rowbytes(png, info);
    png_byte* image_data = new png_byte[row_bytes * height];
    if (!image_data) {
        png_destroy_read_struct(&png, &info, &info_end);
        zip_fclose(file);
        zip_close(apk);
        throw "Could not allocate memory for PNG image data";
    }

    png_bytep* row_pointers = new png_bytep[height];
    if (!row_pointers) {
        png_destroy_read_struct(&png, &info, &info_end);
        delete[] image_data;
        zip_fclose(file);
        zip_close(apk);
        throw "Could not allocate memory for PNG row pointers";
    }

    for (int i = 0; i < height; i++)
        row_pointers[height - 1 - i] = image_data + i * row_bytes;

    png_read_image(png, row_pointers);

    GLuint texture;
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    GLenum format = GL_RGBA;
    glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0,
                 format, GL_UNSIGNED_BYTE, image_data);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    png_destroy_read_struct(&png, &info, &info_end);
    delete[] image_data;
    delete[] row_pointers;
    zip_fclose(file);
    zip_close(apk);
    return texture;
}
4

2 に答える 2

2

さらに試行錯誤を繰り返した後、必死にグーグル検索に戻ったところ、探していた機能を正確に実行するコード サンプルを見つけました。

秘密は、基本的に次のような OpenGL テクスチャを作成することです。

int texture_width = next_power_of_two(width);
int texture_height = next_power_of_two(height);

GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

if (texture_width != width || texture_height != height) {
    glTexImage2D(GL_TEXTURE_2D, 0, format, texture_width,
                 texture_height, 0, format, GL_UNSIGNED_BYTE, NULL);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format,
                    GL_UNSIGNED_BYTE, image_data);
} else
    glTexImage2D(GL_TEXTURE_2D, 0, format, texture_width,
                 texture_height, 0, format, GL_UNSIGNED_BYTE,
                 image_data);

画像を元のサイズでレンダリングするには、x/y テクスチャ座標を次のように計算する必要があります (単に を使用するのではなく1)。

float x_coordinate = (width - 0.5f) / texture_width;
float y_coordinate = (height - 0.5f) / texture_height;
于 2013-01-05T06:04:51.537 に答える
1

ES 1.1 は、拡張機能のない NPOT テクスチャを公式にサポートしていません。一部の実装では誤って動作する可能性がありますが、それは単なる「運」です。

通常のアプローチは、NPOT 画像をより大きな POT テクスチャにパックし、それに応じてテクスチャ座標を調整することです。これは、実行時にプログラムで行うことも (「パッキング」)、ツールチェーンで行うこともできます (ほとんどの場合、アート プログラム)。

于 2013-01-04T09:41:28.963 に答える