簡體   English   中英

加載不同的紋理 Opengl:減慢程序

[英]Load different textures Opengl: slows the program

我在 3d 中實現了一個迷宮。 它工作正常,但現在我必須將紋理放入其中。 我想加載不同的紋理,具體取決於它是牆壁、食物還是走廊。 我找到了每次需要紋理時調用 LoadTexture 的方法。

我遇到了一個使用函數 Readjpeg 和 LoadTexture 的模板。 但是結果太慢了。 程序邏輯很好,但是動作很慢。 假設因為我多次從文件中讀取,然后空閑時間不像以前那樣被調用。

v

oid Maze::draw3D(int w, int h){

    if (rows == 0 || columns == 0)
          throw std::out_of_range("Error: El numero columnas o filas no puede ser cero. Error división por cero");
    if (rows > h || columns > w)
              throw std::out_of_range("Error: La ventana tiene que tener un tamaño mayor a las fila por columnas");

      int numberRow, numberColumn;

      int widthRatio =int(w / columns);
      int heightRatio = int(h / rows);
      //int numberRow;
      GLUquadric *sphere=gluNewQuadric();

      for(numberRow=0;numberRow < rows; numberRow++)
        for(numberColumn=0; numberColumn< columns;numberColumn++)
            if(!isCenter(numberRow,numberColumn)){
            if( map[numberRow][numberColumn]==WALL ) {

            //Selecciona el color actual con el que dibujar. Parámetros R G y B, rango [0..1], así que estamos ante el color azul
            //glColor3f(0.0, 0.0, 1.0);

            /*glBegin() comienza una secuencia de vértices con los que se construirán primitivas. El tipo de primitivas viene dado por el parámetro de glBegin(), en este caso GL_QUADS.
             * Al haber cuatro vértices dentro de la estructura, está definiendo un cuadrado. glEnd() simplemente cierra la estructura.
             *
             */


            //las x son iguales cambian las y
        //ysim =(rows-numberRow);
        //numberRow=numberRow;

        //Pared suelo
        glColor3f(1.0, 0.0, 0.0); // Red = rgb <1, 0, 0>
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),0,(numberRow*heightRatio)-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),0,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),0,(numberRow+1)*heightRatio-(HEIGHT/2));       
        //Vertice arriba derecha
        glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),0,(numberRow)*heightRatio-(HEIGHT/2));     
        glEnd();

/*
        //Pared techo
        glColor3f(1.0, 0.0, 0.0); // Red = rgb <1, 0, 0>
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow*heightRatio)-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice arriba derecha
        glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),DEPTH,(numberRow)*heightRatio-(HEIGHT/2));
        //glVertex3i(50,-50,50);
        glEnd();
    */


          //Pared exterior (las x mas izquierda) (1)
        glColor3f(0.0, 1.0, 0.0); //Green = rgb <0, 1, 0>
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),0,(numberRow*heightRatio)-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),0,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i( ((numberColumn)*widthRatio)-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice arriba derecha
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow*heightRatio)-(HEIGHT/2));
        glEnd();

        //Pared exterior ( las y mas abajo) (2)
        glColor3f(0.0, 0.0, 1.0);//Blue = rgb <0, 0, 1>
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i(((numberColumn)*widthRatio)-(WIDTH/2),0, (numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),0, (numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice arriba derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),DEPTH, (numberRow+1)*heightRatio-(HEIGHT/2));
        glEnd();

      //Pared exterior ( las x mas abajo) (3)106;90;205
        glColor3f(1.0, 0.5, 0.0); //Orange = color red 1 green 0.5 blue 0.0
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),DEPTH, (numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),0, (numberRow+1)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),0, (numberRow)*heightRatio-(HEIGHT/2));
        //Vertice arriba derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),DEPTH, (numberRow)*heightRatio-(HEIGHT/2));
        glEnd();

      //Pared exterior ( las y mas arriba) (4)
        glColor3f(0.752, 0.752, 0.752); //Grey = color red 0.752941 green 0.752941 blue 0.752941
        glBegin(GL_QUADS);
        //Vertice arriba izquierda
        glVertex3i((numberColumn*widthRatio)-(WIDTH/2),0, (numberRow)*heightRatio-(HEIGHT/2));
        //Vertice abajo izquierda
        glVertex3i(((numberColumn)*widthRatio)-(WIDTH/2),DEPTH, (numberRow)*heightRatio-(HEIGHT/2));
        //Vertice abajo derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),DEPTH, (numberRow)*heightRatio-(HEIGHT/2));
        //Vertice arriba derecha
        glVertex3i(((numberColumn+1)*widthRatio)-(WIDTH/2),0, (numberRow)*heightRatio-(HEIGHT/2));
        glEnd();

      //Textura pared techo
     glEnable(GL_TEXTURE_2D);

                 glBindTexture(GL_TEXTURE_2D,0);
                  LoadTexture("Groundplant64x64.jpg",64);
                  glBegin(GL_QUADS);
                  glTexCoord2f(-4.0,0.0); glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow*heightRatio)-(HEIGHT/2));
                  glTexCoord2f(4.0,0.0); glVertex3i((numberColumn*widthRatio)-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
                  glTexCoord2f(4.0,4.0); glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),DEPTH,(numberRow+1)*heightRatio-(HEIGHT/2));
                  glTexCoord2f(-4.0,4.0); glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),DEPTH,(numberRow)*heightRatio-(HEIGHT/2));
                  glEnd();
      glDisable(GL_TEXTURE_2D);


        }
        else if(map[numberRow][numberColumn] == FOOD){

            //Selecciona el color actual con el que dibujar. Parámetros R G y B, rango [0..1], así que estamos ante el color blanco
                        glColor3f(1.0,1.0,0.0); //Orange

                        /*glBegin() comienza una secuencia de vértices con los que se construirán primitivas. El tipo de primitivas viene dado por el parámetro de glBegin(), en este caso GL_QUADS.
                         * Al haber cuatro vértices dentro de la estructura, está definiendo un cuadrado. glEnd() simplemente cierra la estructura.
                         *
                         */

                        //GLUquadric *sphere=gluNewQuadric();
                            gluQuadricDrawStyle( sphere, GLU_FILL);
                            gluQuadricNormals( sphere, GLU_SMOOTH);
                            gluQuadricOrientation( sphere, GLU_OUTSIDE);
                            gluQuadricTexture( sphere, GL_TRUE);

                            glPushMatrix();
                            glTranslated(((numberColumn+0.5)*widthRatio)-(WIDTH/2),DEPTH/3,(numberRow+0.5)*heightRatio-(HEIGHT/2) );
                            //glRotated(45,1,1,1);
                            glEnable(GL_TEXTURE_2D);
                            glBindTexture(GL_TEXTURE_2D,0);
                            LoadTexture("Flames64x64.jpg",64);
                            gluSphere(sphere,5.0,50,50);//(numberColumn+1)*widthRatio)-(WIDTH/2),0, (ysim)*heightRatio-(HEIGHT/2)
                            glPopMatrix();
                            glDisable(GL_TEXTURE_2D);
        }

        else if(map[numberRow][numberColumn] == PASSAGE){

                    //Selecciona el color actual con el que dibujar. Parámetros R G y B, rango [0..1], así que estamos ante el color blanco
                                glColor3f(1.0,0.5,0.0);

                                 glEnable(GL_TEXTURE_2D);
                                             glBindTexture(GL_TEXTURE_2D,0);
                                              LoadTexture("FloorsMedieval64x64.jpg",64);
                                                  glBegin(GL_QUADS);
                                                  glTexCoord2f(-4.0,0.0); glVertex3i((numberColumn*widthRatio)-(WIDTH/2),2,(numberRow*heightRatio)-(HEIGHT/2));
                                                  glTexCoord2f(4.0,0.0); glVertex3i((numberColumn*widthRatio)-(WIDTH/2),2,(numberRow+1)*heightRatio-(HEIGHT/2));
                                                  glTexCoord2f(4.0,4.0); glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),2,(numberRow+1)*heightRatio-(HEIGHT/2));
                                                  glTexCoord2f(-4.0,4.0); glVertex3i((numberColumn+1)*widthRatio-(WIDTH/2),2,(numberRow)*heightRatio-(HEIGHT/2));
                                                  glEnd();
                                  glDisable(GL_TEXTURE_2D);

                }

        }


}

我們的老師傳給我們以下代碼來使用:

/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
void Maze::ReadJPEG(char *filename,unsigned char **image,int *width, int *height)
{
  struct jpeg_decompress_struct cinfo;
  struct jpeg_error_mgr jerr;
  FILE * infile;
  unsigned char **buffer;
  int i,j;

  cinfo.err = jpeg_std_error(&jerr);
  jpeg_create_decompress(&cinfo);


  if ((infile = fopen(filename, "rb")) == NULL) {
    printf("Unable to open file %s\n",filename);
    exit(1);
  }

  jpeg_stdio_src(&cinfo, infile);
  jpeg_read_header(&cinfo, TRUE);
  jpeg_calc_output_dimensions(&cinfo);
  jpeg_start_decompress(&cinfo);

  *width = cinfo.output_width;
  *height  = cinfo.output_height;


  *image=(unsigned char*)malloc(cinfo.output_width*cinfo.output_height*cinfo.output_components);

  buffer=(unsigned char **)malloc(1*sizeof(unsigned char **));
  buffer[0]=(unsigned char *)malloc(cinfo.output_width*cinfo.output_components);


  i=0;
  while (cinfo.output_scanline < cinfo.output_height) {
    jpeg_read_scanlines(&cinfo, buffer, 1);

    for(j=0;j<cinfo.output_width*cinfo.output_components;j++)
      {
    (*image)[i]=buffer[0][j];
    i++;
      }

    }

  free(buffer);
  jpeg_finish_decompress(&cinfo);
}



/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
void Maze::LoadTexture(char *filename,int dim)
{
  unsigned char *buffer;
  unsigned char *buffer2;
  int width,height;
  long i,j;
  long k,h;

  ReadJPEG(filename,&buffer,&width,&height);

  buffer2=(unsigned char*)malloc(dim*dim*3);

  //-- The texture pattern is subsampled so that its dimensions become dim x dim --
  for(i=0;i<dim;i++)
    for(j=0;j<dim;j++)
      {
    k=i*height/dim;
    h=j*width/dim;

    buffer2[3*(i*dim+j)]=buffer[3*(k*width +h)];
    buffer2[3*(i*dim+j)+1]=buffer[3*(k*width +h)+1];
    buffer2[3*(i*dim+j)+2]=buffer[3*(k*width +h)+2];

      }

  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
  glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,dim,dim,0,GL_RGB,GL_UNSIGNED_BYTE,buffer2);

  free(buffer);
  free(buffer2);
}

如果有另一種方法可以在內存中使用不同的紋理(jpeg 中的 64x64 像素圖像)或任何提高速度的想法。 動畫非常非常緩慢。

謝謝

按照@datenwolf 的建議進行更新

我的 readJPEG.cpp

#include "ReadJPEG.h"


/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
int ReadJPEG(
    std::string const filename,
    std::vector<uint8_t> *image,
    int *width, int *height )
{
    if( !image ) {
        return -1;
    }

    FILE * const infile = fopen(filename, "rb");
    if( !infile ) {
        std::cerr
            << "error opening file "
            << filename
            << " : "
            << strerror(errno)
            << std::endl;
        return -2;
    }

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, infile);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_calc_output_dimensions(&cinfo);
    jpeg_start_decompress(&cinfo);

    if( width )  { *width  = cinfo.output_width;  }
    if( height ) { *height = cinfo.output_height; }

    size_t const stride = cinfo.output_width * cinfo.output_components;
   // image->resize(cinfo.output.height * stride);
    image->resize(cinfo.output_height * stride);
    jpeg_read_scanlines(&cinfo, &(*image)[0], cinfo.output_height);
    jpeg_finish_decompress(&cinfo);
    //jpeg_read_scanlines(&cinfo, &(*image)[0], cinfo.output_height);
    return 0;
}

MyLoadTexture.cpp

#include "MyLoadTexture.h"

//using namespace std;

GLuint MyLoadTexture(std::string const filename)
{
    GLuint texname = 0;
    /* this is actually tied to the OpenGL context, so this should
    * actually be a map GLcontext -> std::string -> texturename */
    static std::map<std::string, GLuint> loaded_textures;
    if( loaded_textures.find(filename) != loaded_textures.end() ) {
        texname = loaded_textures[filename];
        glBindTexture(GL_TEXTURE_2D, texname);
        return texname;
    }

    int width,height;
    std::vector<uint8_t> image;
    if( ReadJPEG(filename, &image, &width, &height) ) {
        std::cerr
            << "error reading JPEG"
            << std::endl;
        return 0;
    }

    glGenTextures(1, &texname);
    if( !texname ) {
        std::cerr
            << "error generating OpenGL texture name"
            << std::endl;
        return 0;
    }

    glBindTexture(GL_TEXTURE_2D, texname);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

   /* glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGB,
        width, height, 0,
        GL_RGB,
        GL_UNSIGNED_BYTE, buffer );
    */
    glTexImage2D(
           GL_TEXTURE_2D, 0, GL_RGB,
           width, height, 0,
           GL_RGB,
           GL_UNSIGNED_BYTE, &texname);

    loaded_textures[filename] = texname;

    return texname;
}

注意我改變了@datewnwolf glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer ); by(因為緩沖區不再存在):
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 寬度, 高度, 0, GL_RGB, GL_UNSIGNED_BYTE, &texname);

還有一個詞法錯誤: image->resize(cinfo.output.height * stride); 到圖像->調整大小(cinfo.output_height * stride);

我面臨這個錯誤:

說明 資源路徑位置類型“fopen”未在此范圍內聲明 ReadJPEG.cpp /RandomMaze3d line 22 C/C++ 問題

說明 資源路徑位置類型無法將參數 '2' 的 'unsigned char*' 轉換為 'JSAMPARRAY {aka unsigned char**}' 到 'JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY, JDIMENSION)' ReadJPEG.cpp /RandomMaze3d line 50 C/C++問題

語義錯誤(可能與上述錯誤有關):描述資源路徑位置類型無效參數'候選對象是:_IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error

描述資源路徑位置類型無效參數'候選是:unsigned int jpeg_read_scanlines(jpeg_decompress_struct *, unsigned char * *, unsigned int) ' ReadJPEG.cpp /RandomMaze3d line 50 Semantic Error

我也可以保存 use int 而不是 unint_8 和 String 或 char* 而不是 std:string ?? 不是嗎?

更新執行錯誤:

@datenwolf 非常感謝。 我今天早上一直在工作,我可以毫無錯誤地執行。 但是現在我面臨一個奇怪的執行錯誤,我在一個地方更改為以 MyLoadTexture 和新的 ReadJPEG 開始 LoadTextures:

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,0);
MyLoadTexture("Groundplant64x64.jpg");
glBegin(GL_QUADS); .... 

給我一個:當我啟動 Groundplant64x64,jpg 時,應用程序傳輸的掃描線太少....文件沒有損壞,因為我可以打開它...我在谷歌搜索但沒有得到答案。

Groundplants 是 96x64 像素(因為我在保存它時犯了一個錯誤)但我也嘗試過使用 fire.jpg,它是 64x64。 jpg 以 85% 的質量保存。我也嘗試保存 100% 和相同的錯誤。

更新執行錯誤2:

@datenwolf 看到我的更新錯誤。 現在,如果我用一個文件運行我以前的函數 loadTextures,它可以很好地使用 64 作為參數,就像開始時一樣。 但是,如果我調用 MyLoadTexture,則窗口會消失而沒有任何錯誤消息。 所以帶有所有紋理的地圖

靜態 std::map 加載紋理;

它不應該在 MyLoadTexture 之外並定義為全局變量。 我想當函數結束時,loaded_textures 消失(它從內存中釋放出來)並假設它變成空白。

問題很明顯在 MyLoadTexture 中,就像我用 LoadTextures("fire.jpg", 64); 一切順利。 然后如果我再次使用 MyLoadTexture("fire.jpg"); 窗口消失(試圖繪制迷宮)。

如前所述 MyLoadTexture 和 ReadJPEG 是公共全局函數,因為我需要從迷宮以外的其他類調用它們,例如 Ghost、Pacman 類。

任何其他建議請。

LoadTexture正在經歷從磁盤(緩存)讀取文件解析它,然后加載數據的整個麻煩。 有趣的是,您基本上利用了可追溯到 OpenGL-1.0(已在 IIRC 1992 中發布;天哪,我什至沒有相關規范)的時代錯誤,您可以在其中將圖像數據加載到紋理0 這樣做不是很聰明。

相反,只需將所有紋理加載一次,每個紋理都加載到它自己的紋理對象中。 您會看到那里所有的glBindTexture調用。 第二個參數是要使用的紋理的“名稱”。 因此,在加載圖像時,您首先要創建“名稱”,為要與glGenTextures一起使用的每個圖像創建一個名稱,然后綁定每個名稱,加載圖像,然后轉到下一個圖像。

當繪制所有你需要做的就是glBindTexture你想要使用的紋理,不需要在那里加載任何東西,因為它已經加載了。

由於評論中的要求而更新

所以在你的代碼中你有很多這種模式的出現:

glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,0);
LoadTexture( a_filename );
/* --- draw something --- */
glDisable(GL_TEXTURE_2D);

發生的情況是您綁定 OpenGL 紋理 0(允許與 OpenGL-1.0 保持兼容)並使用 LoadTexture 將圖像加載到其中。 順便說一句,將參數dim至 LoadTexture 是完全沒有必要的,而且實際上是危險的 JPEG 文件已經包含您需要的所有信息。

相反,你應該用這樣的東西替換它:

首先稍微改變LoadTexture 把它從迷宮課上撕下來,它不屬於那里。 使它成為一個全局函數。 讓它生成一個 OpenGL 紋理名稱,將紋理加載到其中並返回紋理名稱。 此外,所有的二次抽樣都是瘋狂的; OpenGL 可以處理任意紋理尺寸,只需使用它。 最后但並非最不重要的一點是使用貼圖將文件名映射到紋理名稱,這樣已經加載的圖像文件不會重復加載。

/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
#include <map>
#include <string>
GLuint LoadTexture(std::string const filename)
{
    GLuint texname = 0;
    /* this is actually tied to the OpenGL context, so this should
    * actually be a map GLcontext -> std::string -> texturename */
    static std::map<std::string, GLuint> loaded_textures;
    if( loaded_textures.find(filename) != loaded_textures.end() ) {
        texname = loaded_textures[filename];
        glBindTexture(GL_TEXTURE_2D, texname);
        return texname;
    }

    int width,height;
    std::vector<uint8_t> image;
    if( ReadJPEG(filename, &image, &width, &height) ) {
        std::cerr
            << "error reading JPEG"
            << std::endl;
        return 0;
    }

    glGenTextures(1, &texname);
    if( !texname ) {
        std::cerr
            << "error generating OpenGL texture name"
            << std::endl;
        return 0;
    }

    glBindTexture(GL_TEXTURE_2D, texname);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);

    glTexImage2D(
        GL_TEXTURE_2D, 0, GL_RGB,
        width, height, 0,
        GL_RGB,
        GL_UNSIGNED_BYTE, &image[0] );

    loaded_textures[filename] = texname;

    return texname;
}

應用這些更改后, LoadTexture將只加載一次圖像,並且在以后的調用中使用文件名映射到已加載的 OpenGL 紋理,而不是生成新的紋理。 您可以將它用作替代品,並且它的編寫方式將“適用於”其余代碼。

更新 2,ReadJPEG 的改進版本

#include <string>
#include <vector>
#include <stdint.h>
#include <string.h>
#include <errno.h>
/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
int ReadJPEG(
    std::string const filename,
    std::vector<uint8_t> *image,
    int *width, int *height )
{
    if( !image ) {
        return -1;
    }

    FILE * const infile = fopen(filename.c_str(), "rb");
    if( !infile ) {
        std::cerr
            << "error opening file "
            << filename
            << " : " 
            << strerror(errno)
            << std::endl;
        return -2;
    }

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);

    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, infile);
    jpeg_read_header(&cinfo, TRUE);
    jpeg_calc_output_dimensions(&cinfo);
    jpeg_start_decompress(&cinfo);

    if( width )  { *width  = cinfo.output_width;  }
    if( height ) { *height = cinfo.output_height; }

    size_t const stride = cinfo.output_width * cinfo.output_components;
    image->resize(cinfo.output.height * stride);

    for(size_t i = 0; i < cinfo.output_height;) {
        uint8_t * const row =  &(*image)[stride * i];
        i += jpeg_read_scanlines(&cinfo, (unsigned char**)&row, 1);
    }
    jpeg_finish_decompress(&cinfo);

    fclose(infile);
    return 0;
}

請注意,這個新版本在合理的情況下使用了 RAII 和適當的 C++ 習語; 我強烈建議不要使用引用,因為引用是偽裝的指針,可能會絆倒你。 真實的、顯式的指針可防止您陷入此類陷阱。

由於問題更新而更新3:

說明 資源路徑位置類型“fopen”未在此范圍內聲明 ReadJPEG.cpp /RandomMaze3d line 22 C/C++ 問題

在 ReadJPEG.cpp 的頂部添加一個#include <stdio.h> - 我也使用iostream來發出錯誤消息,所以也在那里添加#include <iostream> ,並在 LoadTexture.cpp 中添加一個很好的衡量標准。

說明 資源路徑位置類型無法將參數 '2' 的 'unsigned char*' 轉換為 'JSAMPARRAY {aka unsigned char**}' 到 'JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY, JDIMENSION)' ReadJPEG.cpp /RandomMaze3d line 50 C/C++問題 (...) 描述 資源路徑位置類型無效參數 ' 候選是: unsigned int jpeg_read_scanlines(jpeg_decompress_struct *, unsigned char * *, unsigned int) ' ReadJPEG.cpp /RandomMaze3d line 50 Semantic Error

請參閱我編輯的 ReadJPEG 版本(geesh,他使用雙指針間接尋址設計了 libjpeg API)。 無論如何,每個掃描線的循環和輔助指針變量都無法修復。

語義錯誤(可能與上述錯誤有關):描述資源路徑位置類型無效參數'候選對象是:_IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error

另請參閱我編輯過的 ReadJPEG 版本

我也可以節省使用 int 而不是 unint_8

不!!!

對於一個sizeof(int) != sizeof(uint8_t) 你可以代替uint8_tunsigned char ,雖然,但一個大小char不是刻在石頭上(它通常是8位,但不總是)。 libjpeg API 使用unsigned char作為數據類型而不是像uint8_t這樣的真正固定大小的數據類型,它在任何情況下都是 8 位大小,這有點可恥。

和 String 或 char* 而不是 std:string ?? 不是嗎?

我不知道您指的是哪種特定的String類型。 永遠不要在 C++ 代碼中使用 C 風格的char* “字符串”,除非您與純 C API 交互。 哎呀,我在很大程度上更喜歡 C 而不是 C++,即使在那里我也盡可能遠離char*並使用一些字符串抽象,如 uStr 或類似的。 char*字符串是完全危險的。

C++ 有一個標准的(作為語言標准庫的一部分)字符串類型。 它被稱為std::string ,如果您正在編寫 C++ 代碼,則可以使用它。 這是沒有爭議的。

同時保持 C++ 標准庫類型將為您節省顯式分配和刪除內存的所有麻煩。 所有這些血腥的細節都很好地隱藏在 STL 的分配器中,如果您虔誠地堅持 RAII(= 從不明確使用newdelete操作),您將永遠不會遇到內存泄漏; 當然,您不能總是堅持使用 RAII。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM