简体   繁体   English

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

[英]Load different textures Opengl: slows the program

Im implementing a Maze in 3d.我在 3d 中实现了一个迷宫。 It works fine, but now i have to put textures in it.它工作正常,但现在我必须将纹理放入其中。 Id like to load different textures depending if its a wall or food or corridor.我想加载不同的纹理,具体取决于它是墙壁、食物还是走廊。 I found the way calling LoadTexture every time i need a texture.我找到了每次需要纹理时调用 LoadTexture 的方法。

Ive met a template using the functions Readjpeg and LoadTexture.我遇到了一个使用函数 Readjpeg 和 LoadTexture 的模板。 But the result is too slow.但是结果太慢了。 The program logic is good, but movements are very slow.程序逻辑很好,但是动作很慢。 Suppose because i read from file many times and the idle then is not called as times as before.假设因为我多次从文件中读取,然后空闲时间不像以前那样被调用。

v 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);

                }

        }


}

Our teacher pass us the following code to use:我们的老师传给我们以下代码来使用:

/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
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);
}

If theres another way that i could have different textures ( are 64x64 pixels images in jpeg) in memory or any ideas to improve the speed.如果有另一种方法可以在内存中使用不同的纹理(jpeg 中的 64x64 像素图像)或任何提高速度的想法。 The animation is very very slow.动画非常非常缓慢。

Thanks谢谢

Update as suggested by @datenwolf按照@datenwolf 的建议进行更新

my readJPEG.cpp我的 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 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;
}

Note ive changed @datewnwolf glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer );注意我改变了@datewnwolf glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer ); by ( as buffer doesnt exist anymore): by(因为缓冲区不再存在):
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, &texname); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 宽度, 高度, 0, GL_RGB, GL_UNSIGNED_BYTE, &texname);

also an lexical error: image->resize(cinfo.output.height * stride);还有一个词法错误: image->resize(cinfo.output.height * stride); to image->resize(cinfo.output_height * stride);到图像->调整大小(cinfo.output_height * stride);

Im facing this errors:我面临这个错误:

Description Resource Path Location Type 'fopen' was not declared in this scope ReadJPEG.cpp /RandomMaze3d line 22 C/C++ Problem说明 资源路径位置类型“fopen”未在此范围内声明 ReadJPEG.cpp /RandomMaze3d line 22 C/C++ 问题

Description Resource Path Location Type cannot convert 'unsigned char*' to 'JSAMPARRAY {aka unsigned char**}' for argument '2' to 'JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY, JDIMENSION)' ReadJPEG.cpp /RandomMaze3d line 50 C/C++ Problem说明 资源路径位置类型无法将参数 '2' 的 'unsigned char*' 转换为 'JSAMPARRAY {aka unsigned char**}' 到 'JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY, JDIMENSION)' ReadJPEG.cpp /RandomMaze3d line 50 C/C++问题

Semantic errors ( perhaps related with above errors): Description Resource Path Location Type Invalid arguments ' Candidates are: _IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error语义错误(可能与上述错误有关):描述资源路径位置类型无效参数'候选对象是:_IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error

Description Resource Path Location Type Invalid arguments ' Candidates are: unsigned int jpeg_read_scanlines(jpeg_decompress_struct *, unsigned char * *, unsigned int) ' ReadJPEG.cpp /RandomMaze3d line 50 Semantic Error描述资源路径位置类型无效参数'候选是:unsigned int jpeg_read_scanlines(jpeg_decompress_struct *, unsigned char * *, unsigned int) ' ReadJPEG.cpp /RandomMaze3d line 50 Semantic Error

Also i could save use int instead of unint_8 and String or char* instead of std:string ??我也可以保存 use int 而不是 unint_8 和 String 或 char* 而不是 std:string ?? Isnt it ?不是吗?

Update execution error:更新执行错误:

@datenwolf thanks a lot. @datenwolf 非常感谢。 ive been working this morning and i can execute without errors.我今天早上一直在工作,我可以毫无错误地执行。 But now im facing a weird execution error, ive changed in one place to begin the LoadTextures with MyLoadTexture and new ReadJPEG as:但是现在我面临一个奇怪的执行错误,我在一个地方更改为以 MyLoadTexture 和新的 ReadJPEG 开始 LoadTextures:

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

Gives me an: Application transferred too few scanlines when i launch Groundplant64x64,jpg....the file is not corrupted as i can open it...Im googleing but dont get answer.给我一个:当我启动 Groundplant64x64,jpg 时,应用程序传输的扫描线太少....文件没有损坏,因为我可以打开它...我在谷歌搜索但没有得到答案。

Groundplants is 96x64 pixels ( as i made a mistake saving it) but ive tried also with fire.jpg which is 64x64. Groundplants 是 96x64 像素(因为我在保存它时犯了一个错误)但我也尝试过使用 fire.jpg,它是 64x64。 jpg is saved at 85% of quality.I also have tried to save a 100% and same error. jpg 以 85% 的质量保存。我也尝试保存 100% 和相同的错误。

Update execution error 2:更新执行错误2:

@datenwolf see my update error. @datenwolf 看到我的更新错误。 Now if i run my previous function loadTextures with a file it works well with 64 as parameter as at the beginning.现在,如果我用一个文件运行我以前的函数 loadTextures,它可以很好地使用 64 作为参数,就像开始时一样。 But if i call MyLoadTexture just the window disappear without any error message.但是,如果我调用 MyLoadTexture,则窗口会消失而没有任何错误消息。 So the map with all the textures所以带有所有纹理的地图

static std::map loaded_textures;静态 std::map 加载纹理;

Shouldnt it be outside MyLoadTexture and defined as global variable.它不应该在 MyLoadTexture 之外并定义为全局变量。 I suppose that when the function ends, loaded_textures dissapear ( it gets free from memory) and suppose it gets blank.我想当函数结束时,loaded_textures 消失(它从内存中释放出来)并假设它变成空白。

The problem is clearly in MyLoadTexture as if i substitute by LoadTextures("fire.jpg", 64);问题很明显在 MyLoadTexture 中,就像我用 LoadTextures("fire.jpg", 64); all goes well.一切顺利。 Then if i use again MyLoadTexture("fire.jpg");然后如果我再次使用 MyLoadTexture("fire.jpg"); the window disappears ( in the attempt of drawing the maze).窗口消失(试图绘制迷宫)。

As told before MyLoadTexture and ReadJPEG are public global functions as i need to call them from other classes than Maze as for example Ghost, Pacman classes.如前所述 MyLoadTexture 和 ReadJPEG 是公共全局函数,因为我需要从迷宫以外的其他类调用它们,例如 Ghost、Pacman 类。

Any other suggestion please.任何其他建议请。

LoadTexture is going through the whole hassle of reading the file from disk (cache) parsing it, then load the data. LoadTexture正在经历从磁盘(缓存)读取文件解析它,然后加载数据的整个麻烦。 And funny enough, you essentially exploit an anachronism that dates back to OpenGL-1.0 (that's been released in IIRC 1992; geesh I don't even have the spec for that around) where you could load image data into texture 0 .有趣的是,您基本上利用了可追溯到 OpenGL-1.0(已在 IIRC 1992 中发布;天哪,我什至没有相关规范)的时代错误,您可以在其中将图像数据加载到纹理0 That's not very smart to do.这样做不是很聪明。

Instead just load all the textures once, each into it's own texture object.相反,只需将所有纹理加载一次,每个纹理都加载到它自己的纹理对象中。 You see all those glBindTexture calls you have there.您会看到那里所有的glBindTexture调用。 The second parameter is an "name" for which texture to use.第二个参数是要使用的纹理的“名称”。 So when loading the images you'd first create "names", one for each image you want to use with glGenTextures , then bind each name, load the image and then go to the next image.因此,在加载图像时,您首先要创建“名称”,为要与glGenTextures一起使用的每个图像创建一个名称,然后绑定每个名称,加载图像,然后转到下一个图像。

When drawing all you have to do then is just glBindTexture the texture you want to use, no need to load anything there, because it's already loaded.当绘制所有你需要做的就是glBindTexture你想要使用的纹理,不需要在那里加载任何东西,因为它已经加载了。

Update due to request in comment由于评论中的要求而更新

So in your code you have a lot of occurrences of this pattern:所以在你的代码中你有很多这种模式的出现:

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

What happens there is that you bind OpenGL texture 0 (which is allowed to stay compatible with OpenGL-1.0) and load a image into it using LoadTexture.发生的情况是您绑定 OpenGL 纹理 0(允许与 OpenGL-1.0 保持兼容)并使用 LoadTexture 将图像加载到其中。 BTW, that parameter dim to LoadTexture is totally unnecessary and in fact dangerous .顺便说一句,将参数dim至 LoadTexture 是完全没有必要的,而且实际上是危险的 JPEG files already have all the information you need. JPEG 文件已经包含您需要的所有信息。

Instead you should replace it with something like this:相反,你应该用这样的东西替换它:

First change LoadTexture a little bit.首先稍微改变LoadTexture Rip it out of the Maze class, it does not belong there.把它从迷宫课上撕下来,它不属于那里。 Make it a global function.使它成为一个全局函数。 Let it generate a OpenGL texture name, load the texture into it and return the texture name.让它生成一个 OpenGL 纹理名称,将纹理加载到其中并返回纹理名称。 Also all that subsampling is crazy;此外,所有的二次抽样都是疯狂的; OpenGL can work with arbitrary texture dimenstions, just use that. OpenGL 可以处理任意纹理尺寸,只需使用它。 Last but not least use a map to map filenames to texture names, so that image files that are already loaded are not redundantly reloaded.最后但并非最不重要的一点是使用贴图将文件名映射到纹理名称,这样已经加载的图像文件不会重复加载。

/*--------------------------------------------------------*/
/*--------------------------------------------------------*/
#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;
}

With these changes applied LoadTexture will load an image only once, and on later calls use the filename to map to the already loaded OpenGL texture instead of generating a new one.应用这些更改后, LoadTexture将只加载一次图像,并且在以后的调用中使用文件名映射到已加载的 OpenGL 纹理,而不是生成新的纹理。 You can use it as a drop-in replacement and the way it's written it will "just work" with the rest of your code.您可以将它用作替代品,并且它的编写方式将“适用于”其余代码。

Update 2, improved version for ReadJPEG更新 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;
}

Note that this new version uses RAII and proper C++ idioms where sensible;请注意,这个新版本在合理的情况下使用了 RAII 和适当的 C++ 习语; I strongly advice against using references, since references are pointers in disguise and can trip you up.我强烈建议不要使用引用,因为引用是伪装的指针,可能会绊倒你。 Real, explicit pointer prevent you from tripping into such pitfalls.真实的、显式的指针可防止您陷入此类陷阱。

Update 3 due to question update:由于问题更新而更新3:

Description Resource Path Location Type 'fopen' was not declared in this scope ReadJPEG.cpp /RandomMaze3d line 22 C/C++ Problem说明 资源路径位置类型“fopen”未在此范围内声明 ReadJPEG.cpp /RandomMaze3d line 22 C/C++ 问题

Add a #include <stdio.h> to the top of ReadJPEG.cpp – also I used iostream for emitting error messages so also add #include <iostream> there, and in LoadTexture.cpp for good measure.在 ReadJPEG.cpp 的顶部添加一个#include <stdio.h> - 我也使用iostream来发出错误消息,所以也在那里添加#include <iostream> ,并在 LoadTexture.cpp 中添加一个很好的衡量标准。

Description Resource Path Location Type cannot convert 'unsigned char*' to 'JSAMPARRAY {aka unsigned char**}' for argument '2' to 'JDIMENSION jpeg_read_scanlines(j_decompress_ptr, JSAMPARRAY, JDIMENSION)' ReadJPEG.cpp /RandomMaze3d line 50 C/C++ Problem (…) Description Resource Path Location Type Invalid arguments ' Candidates are: unsigned int jpeg_read_scanlines(jpeg_decompress_struct *, unsigned char * *, unsigned int) ' ReadJPEG.cpp /RandomMaze3d line 50 Semantic Error说明 资源路径位置类型无法将参数 '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

See my edited version of ReadJPEG (geesh, who designed the libjpeg API using a double pointer indirection).请参阅我编辑的 ReadJPEG 版本(geesh,他使用双指针间接寻址设计了 libjpeg API)。 Anyway, nothing a loop over each scanline and a helper pointer variable can't fix.无论如何,每个扫描线的循环和辅助指针变量都无法修复。

Semantic errors ( perhaps related with above errors): Description Resource Path Location Type Invalid arguments ' Candidates are: _IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error语义错误(可能与上述错误有关):描述资源路径位置类型无效参数'候选对象是:_IO_FILE * fopen(const char *, const char *) ' ReadJPEG.cpp /RandomMaze3d line 22 Semantic Error

Also see my edited version of ReadJPEG另请参阅我编辑过的 ReadJPEG 版本

Also i could save use int instead of unint_8我也可以节省使用 int 而不是 unint_8

No!!!不!!!

For one sizeof(int) != sizeof(uint8_t) .对于一个sizeof(int) != sizeof(uint8_t) You could substitute uint8_t for unsigned char though, but the size of a char is not carved in stone (it's usually 8 bits, but not always).你可以代替uint8_tunsigned char ,虽然,但一个大小char不是刻在石头上(它通常是8位,但不总是)。 It's kind of shamefull that the libjpeg API uses unsigned char as a datatype instead of a truely fixed size datatype like uint8_t which always under all circumstances is 8 bits in size. libjpeg API 使用unsigned char作为数据类型而不是像uint8_t这样的真正固定大小的数据类型,它在任何情况下都是 8 位大小,这有点可耻。

and String or char* instead of std:string ??和 String 或 char* 而不是 std:string ?? Isnt it ?不是吗?

I don't know which particular String type you're referring to.我不知道您指的是哪种特定的String类型。 But never use C-style char* "strings" in C++ code, except for when you're interfacing with pure C APIs.永远不要在 C++ 代码中使用 C 风格的char* “字符串”,除非您与纯 C API 交互。 Heck, I largely perfer C over C++ and even there I stay away from char* as far as I can and use some string abstraction like uStr or similar.哎呀,我在很大程度上更喜欢 C 而不是 C++,即使在那里我也尽可能远离char*并使用一些字符串抽象,如 uStr 或类似的。 Naked char* strings are outright dangerous.char*字符串是完全危险的。

C++ has a standard (as part of the language standard library) string type. C++ 有一个标准的(作为语言标准库的一部分)字符串类型。 It's called std::string and if you're writing C++ code you use it.它被称为std::string ,如果您正在编写 C++ 代码,则可以使用它。 This is not debateable.这是没有争议的。

Also keeping to C++ standard library types will save you all the hassle with explicitly allocating and deleting memory.同时保持 C++ 标准库类型将为您节省显式分配和删除内存的所有麻烦。 All those gory details are nicely tucked away down in the allocators of the STL and if you religiously stick to RAII (= never explicitly use new or delete operatos) you'll never experience memory leaks;所有这些血腥的细节都很好地隐藏在 STL 的分配器中,如果您虔诚地坚持 RAII(= 从不明确使用newdelete操作),您将永远不会遇到内存泄漏; of course you can't always stick to RAII.当然,您不能总是坚持使用 RAII。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM