加载不同的纹理Opengl:减慢程序

时间:2015-11-25 09:08:27

标签: c++ opengl textures

我在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,         宽度,高度,0,         GL_RGB,         GL_UNSIGNED_BYTE,缓冲区); by(因为缓冲区不再存在):
    glTexImage2D(            GL_TEXTURE_2D,0,GL_RGB,            宽度,高度,0,            GL_RGB,            GL_UNSIGNED_BYTE,&amp; texname);

也是一个词汇错误: image-&gt; resize(cinfo.output.height * stride); 至 image-&gt; resize(cinfo.output_height * stride);

我面对这个错误:

描述资源路径位置类型 'fopen'未在此范围内声明ReadJPEG.cpp / RandomMaze3d第22行C / C ++问题

描述资源路径位置类型 不能将'unsigned char *'转换为'JSAMPARRAY {aka unsigned char **}'以将参数'2'转换为'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第22行语义错误

描述资源路径位置类型 参数无效' 候选人是: unsigned int jpeg_read_scanlines(jpeg_decompress_struct *,unsigned char * *,unsigned int) 'ReadJPEG.cpp / RandomMaze3d第50行语义错误

另外我可以保存使用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只是窗口消失而没有任何错误消息。所以具有所有纹理的地图

static std :: map loaded_textures;

不应该在MyLoadTexture之外并定义为全局变量。我想当函数结束时,loaded_textures消失(它从内存中释放)并假设它变成空白。

问题显然在MyLoadTexture中,好像我用LoadTextures替换(“fire.jpg”,64);一切顺利。如果我再次使用MyLoadTexture(“fire.jpg”);窗口消失(试图绘制迷宫)。

如前所述,MyLoadTexture和ReadJPEG是公共全局函数,因为我需要从Maze之外的其他类中调用它们,例如Ghost,Pacman类。

请提出任何其他建议。

1 个答案:

答案 0 :(得分:0)

LoadTexture正在经历从磁盘(缓存)解析文件,然后加载数据的整个麻烦。而且很有趣的是,你基本上利用了一个可以追溯到OpenGL-1.0的时代错误(它已经在1992年的IIRC上发布了; geesh我甚至没有那个规范)你可以将图像数据加载到纹理0。这样做并不是很聪明。

相反,只需将所有纹理加载一次,每个纹理都加载到自己的纹理对象中。您会看到所有glBindTexture次来电。第二个参数是&#34; name&#34;要使用哪种纹理。因此,在加载图像时,您首先要创建&#34;名称&#34;,对于要与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将图像加载到其中。顺便说一下,LoadTexture的参数dim是完全没必要的,事实上危险。 JPEG文件已经包含了您需要的所有信息。

相反,你应该用这样的东西替换它:

首先更改LoadTexture一点。将它从Maze类中删除,它不属于那里。使其成为一个全球功能。让它生成一个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第22行C / C ++问题

#include <stdio.h>添加到ReadJPEG.cpp的顶部 - 我也使用iostream发出错误消息,因此还要在其中添加#include <iostream>,并在LoadTexture.cpp中进行测量。< / p>

  

描述资源路径位置类型无法将'unsigned char *'转换为'JSAMPARRAY {aka unsigned char **}'以将参数'2'转换为'JDIMENSION jpeg_read_scanlines(j_decompress_ptr,JSAMPARRAY,JDIMENSION)'ReadJPEG.cpp / RandomMaze3d line 50 C / C ++问题   (......)   说明资源路径位置类型无效参数&#39;候选人是:unsigned int jpeg_read_scanlines(jpeg_decompress_struct *,unsigned char * *,unsigned int)&#39; ReadJPEG.cpp / RandomMaze3d第50行语义错误

查看我编辑的ReadJPEG版本(geesh,使用双指针间接设计libjpeg API)。无论如何,每条扫描线上的循环和辅助指针变量都无法解决。

  

语义错误(可能与上述错误有关):描述资源路径位置类型无效的参数&#39;候选人是:_IO_FILE * fopen(const char *,const char *)&#39; ReadJPEG.cpp / RandomMaze3d第22行语义错误

另见我编辑的ReadJPEG版本

  

我也可以使用int而不是unint_8

否!!!

对于一个sizeof(int) != sizeof(uint8_t)。你可以用uint8_t代替unsigned char,但是char的大小并不是一成不变的(它通常是8位,但并非总是如此)。 libjpeg API使用unsigned char作为数据类型而不是像uint8_t这样的真正固定大小的数据类型,总是在所有情况下都是8位大小。

,这是一种可耻的行为。
  

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

我不知道您指的是哪种String类型。但从不使用C风格char*&#34;字符串&#34;在C ++代码中,除了与纯C API接口的时候。哎呀,我基本上更喜欢C over C ++,甚至在那里我尽可能远离char*并使用像uStr或类似的字符串抽象。裸char*字符串是完全危险的。

C ++有一个标准(作为语言标准库的一部分)字符串类型。它被称为std::string,如果您正在编写C ++代码,则使用它。这不是辩论。

同时保持C ++标准库类型可以省去显式分配和删除内存的所有麻烦。所有这些血淋淋的细节都很好地隐藏在STL的分配器中,如果你虔诚地坚持使用RAII(=从未明确使用newdelete operatos),你将永远不会遇到内存泄漏;当然,你不能总是坚持RAII。