Как я могу загрузить 8-битный bmp с помощью OpenGL?

Вот моя ситуация: мне нужно предварительно загрузить 2000 изображений и отобразить их последовательно, чтобы получить анимацию со скоростью 60 кадров в секунду. В настоящее время я использую OpenGL для загрузки файлов bmp, но из-за нехватки памяти я могу предварительно загрузить только до 500+ изображений. Как я могу решить эту проблему? На данный момент я могу предложить два решения: во-первых, возможно, я смогу загрузить 8-битные bmp-изображения для экономии памяти. Но у меня возникают трудности с использованием glDrawPixels. Во-вторых, если возможно, я могу загрузить jpeg напрямую? Спасибо за любой совет!

Причина отказа от использования видео заключается в том, что мне нужно перейти на скорость анимации, пропустив одно или несколько изображений, как вы можете видеть в коде (imgCount+=stp; // stp означает, сколько изображений нужно экранировать. Это может ускорить видео). А в моей анимации важна частота кадров, фпс ниже 50 показывает мерцание.

Вот код:

void Frame::LoadBMP(void){

 FILE *in;


 in=fopen(file,"rb");//open file 
 if(in==NULL){

     exit(0);
 }
 fread(&(this->bmfh),sizeof(BITMAPFILEHEADER),1,in);//read bmp file header
 fread(&(this->bmih),sizeof(BITMAPINFOHEADER),1,in);//read bmp infomation header

 colours=new RGBQUAD[bmih.biBitCount];
 fread(colours,sizeof(RGBQUAD),bmih.biBitCount,in);//read bmp colour table

 size=bmfh.bfSize-bmfh.bfOffBits;
 tempPixelData=new GLubyte[size];

 if(tempPixelData==NULL) {
     fclose(in);
 }
 fread(tempPixelData,sizeof(GLubyte),size,in);//read bmp image data
 fclose(in);
}

и я буду отображать последовательность изображений, код отображения:

void display(void){

static clock_t start=clock();
static clock_t end=clock();

CurrtempPixelData=msFrame[offset]->tempPixelData;

glEnable(GL_ALPHA_TEST);
glEnable(GL_BLEND);

glDrawPixels(frWidth, frHeight, GL_RGBA, GL_UNSIGNED_BYTE, msFrame[offset]->tempPixelData);

for(int i=0;i<m;i++){
    clock_t c=clock();
}

glutSwapBuffers();
imgCount+=stp; // stp means how many images to escape. it can make video faster.
offset=imgCount%numFrame;
glutPostRedisplay();

}

person Chen Daniel Jinzhao    schedule 16.08.2012    source источник
comment
Вы не можете загрузить растровое изображение с помощью OpenGL, поэтому я думаю, что JPEG не будет проще. Но рассмотрите возможность использования сжатых текстур независимо от того, как вы загружаете фактические данные изображения.   -  person Christian Rau    schedule 16.08.2012


Ответы (2)


Вы не должны использовать glDrawPixels, это устаревшая функциональность. Лучший способ сделать это, вероятно, будет рисовать четырехугольник размером с экран (-1,-1 => 1,1 без какого-либо матричного преобразования), который вы текстурируете с этими изображениями.

Для текстур вы можете указать несколько внутренних форматов в glTexImage2D и подобных функциях. Например, вы можете использовать формат GL_R3_G3_B2​ для получения 8-битного размера, но также можете использовать сжатые форматы, такие как S3TC. Например, вы можете передать COMPRESSED_SRGB_S3TC_DXT1_EXT, что должно уменьшить размер вашего изображения до 4 бит на пиксель, вероятно, с лучшим качеством, чем 8-битный формат. Вы не можете использовать JPEG в качестве формата сжатия в OpenGL (это слишком сложно).

Наконец, почему вы хотите сделать это через OpenGL? перенос изображения в обычное окно, скорее всего, даст вам достаточно хорошую производительность. Затем вы даже можете сохранить свою последовательность изображений как видео и просто скопировать декодированные кадры. В этом случае очень маловероятно, что у вас когда-либо возникнут проблемы с памятью.

person KillianDS    schedule 16.08.2012
comment
Спасибо KillianDS за ваш полезный совет. Я попробую это позже. И по той причине, по которой я использую OpenGL, просто для удобства. На самом деле, я изначально использовал C# для воспроизведения своей последовательности изображений. Но у него есть проблема с перелистыванием, поэтому я перехожу на использование OpenGL. А не могли бы вы объяснить, что вы имеете в виду под переносом изображения в обычное окно? Как этого добиться? Это звучит как простое решение! Так как я совсем новичок в программировании, спасибо за ваше терпение! - person Chen Daniel Jinzhao; 19.08.2012
comment
В большинстве оконных API вы можете рисовать прямо на прямоугольнике в окне/экране, этот общий процесс известен как блиттинг (рисование прямоугольника в другой прямоугольник). Точный интерфейс зависит от API к API, например, в SDL вы должны использовать SDL_BlitSurface - person KillianDS; 20.08.2012

Может быть, вам вообще не нужно иметь 2000 изображений и отображать их со скоростью 60 кадров в секунду? Стабильных 25 кадров в секунду вполне достаточно для любого фильма.

Я призываю вас переосмыслить свою первоначальную проблему и найти более подходящее решение (видео, анимация, векторы, может быть, что-то еще)

Относительно исходного вопроса:

Если вам нужны изображения только один раз - запишите их в память, когда они вам понадобятся, и выбросьте их сразу после показа.

Используйте упакованные изображения DXT. С небольшим ухудшением качества вы получаете постоянную степень сжатия x4/x8.

В настоящее время OpenGL не очень хорошо работает с текстурами с палитрой (многие поставщики имеют плохие реализации). Но вы можете реализовать это с помощью шейдеров.

person Kromster    schedule 16.08.2012
comment
Спасибо, Кром. Ваш совет очень вдохновляет. Вы правы, я могу использовать видео. Но в моем случае мне нужно сделать некоторые манипуляции во время воспроизведения анимации, в частности, мне нужно изменить скорость анимации. А всего у меня 7 разных состояний скорости. Итак, в начале, я думаю, может быть проще записать все изображения в массив, а затем зациклить его. Поэтому у меня проблема с памятью. - person Chen Daniel Jinzhao; 19.08.2012