2012-03-30 146 views
1

我在写一个使用OpenGL(freeglut和glew)的应用程序。C++ OpenGL glTexImage2D访问冲突

我也想要纹理,所以我做了一些关于位图文件格式的研究,并为主标题和另一个DIB标题(信息标题)写了一个结构。

然后我开始写装载机。它会自动将纹理绑定到OpenGL。下面是函数:

static unsigned int ReadInteger(FILE *fp) 
{ 
    int a, b, c, d; 

    // Integer is 4 bytes long. 
    a = getc(fp); 
    b = getc(fp); 
    c = getc(fp); 
    d = getc(fp); 

    // Convert the 4 bytes to an integer. 
    return ((unsigned int) a) + (((unsigned int) b) << 8) + 
      (((unsigned int) c) << 16) + (((unsigned int) d) << 24); 
} 

static unsigned int ReadShort(FILE *fp) 
{ 
    int a, b; 

    // Short is 2 bytes long. 
    a = getc(fp); 
    b = getc(fp); 

    // Convert the 2 bytes to a short (int16). 
    return ((unsigned int) a) + (((unsigned int) b) << 8); 
} 

    GLuint LoadBMP(const char* filename) 
{ 
    FILE* file; 

    // Check if a file name was provided. 
    if (!filename) 
     return 0; 

    // Try to open file. 
    fopen_s(&file, filename, "rb"); 

    // Return if the file could not be open. 
    if (!file) 
    { 
     cout << "Warning: Could not find texture '" << filename << "'." << endl; 
     return 0; 
    } 

    // Read signature. 
    unsigned char signature[2]; 
    fread(&signature, 2, 1, file); 

    // Use signature to identify a valid bitmap. 
    if (signature[0] != BMPSignature[0] || signature[1] != BMPSignature[1]) 
    { 
     fclose(file); 
     return 0; 
    } 

    // Read width and height. 
    unsigned long width, height; 
    fseek(file, 16, SEEK_CUR); // After the signature we have 16bytes until the width. 
    width = ReadInteger(file); 
    height = ReadInteger(file); 

    // Calculate data size (we'll only support 24bpp). 
    unsigned long dataSize; 
    dataSize = width * height * 3; 

    // Make sure planes is 1. 
    if (ReadShort(file) != 1) 
    { 
     cout << "Error: Could not load texture '" << filename << "' (planes is not 1)." << endl; 
     return 0; 
    } 

    // Make sure bpp is 24. 
    if (ReadShort(file) != 24) 
    { 
     cout << "Error: Could not load texture '" << filename << "' (bits per pixel is not 24)." << endl; 
     return 0; 
    } 

    // Move pointer to beggining of data. (after the bpp we have 24 bytes until the data) 
    fseek(file, 24, SEEK_CUR); 

    // Allocate memory and read the image data. 
    unsigned char* data = new unsigned char[dataSize]; 

    if (!data) 
    { 
     fclose(file); 
     cout << "Warning: Could not allocate memory to store data of '" << filename << "'." << endl; 
     return 0; 
    } 

    fread(data, dataSize, 1, file); 

    if (data == NULL) 
    { 
     fclose(file); 
     cout << "Warning: Could no load data from '" << filename << "'." << endl; 
     return 0; 
    } 

    // Close the file. 
    fclose(file); 

    // Create the texture. 
    GLuint texture; 
    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 

    glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); //NEAREST); 
    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 

    gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, width, height, GL_BGR_EXT, GL_UNSIGNED_BYTE, data); 

    return texture; 
} 

我知道,位图的数据被正确读取,因为我输出它的数据到控制台,并用油漆打开图像相比。

这里的问题是这一行:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dibheader.width, 
    dibheader.height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 

大多数我跑这条线与错误的应用程序崩溃的时代:

Unhandled exception at 0x008ffee9 in GunsGL.exe: 0xC0000005: Access violation reading location 0x00af7002.

这是发生错误的拆卸:

movzx  ebx,byte ptr [esi+2] 

这不是我的装载机的错误,因为我已经下载了其他装载机。 我使用的下载的加载程序是NeHe的this one

编辑:(以上代码修订版)

我改写了装载机,但我仍然可以在同一行的崩溃。而不是崩溃,有时我得到(同样的错误消息是我记错)上mlock.c崩溃:

void __cdecl _lock (
     int locknum 
     ) 
{ 

     /* 
     * Create/open the lock, if necessary 
     */ 
     if (_locktable[locknum].lock == NULL) { 

      if (!_mtinitlocknum(locknum)) 
       _amsg_exit(_RT_LOCK); 
     } 

     /* 
     * Enter the critical section. 
     */ 

     EnterCriticalSection(_locktable[locknum].lock); 
} 

就行了:

EnterCriticalSection(_locktable[locknum].lock); 

而且,这里是一个截屏那个时代的应用程序不会崩溃的一个(纹理显然是不正确的): http://i.stack.imgur.com/4Mtso.jpg

EDIT2:

更新后的代码与新的工作。 (答复标记为答案,不包含,需要为这样工作,但它是至关重要的)

+0

该内存位置似乎不是一个指示未初始化指针的位置......我的下一个猜测是OpenGL试图超出数据范围来读取数据。你能否验证你是否指定了正确的数据量来读取? – kevintodisco 2012-03-30 21:21:45

+0

这看起来更像是C而不是C++ – Pubby 2012-03-30 21:26:42

+0

@ktodisco数据大小实际上是正确的。 – zeluisping 2012-03-30 21:52:59

回答

2

我知道,这是很有诱惑力的读取二进制数据是这样

BitmapHeader header; 
BitmapInfoHeader dibheader; 
/*...*/ 
// Read header. 
fread(&header, sizeof(BitmapHeader), 1, file); 

// Read info header. 
fread(&dibheader, sizeof(BitmapInfoHeader), 1, file); 

但你真的不应该这样做的。为什么?由于可以填充结构的内存布局以符合对齐约束(是的,我知道有关包装编译指示),所用编译器的类型大小可能与二进制文件中的数据大小不匹配,并且最后但并非最不重要的endianess可能不匹配。

始终将二进制数据读取到中间缓冲区,您可以使用精确指定的偏移量和输入以明确的方式提取字段。

// Allocate memory for the image data. 
data = (unsigned char*)malloc(dibheader.dataSize); 

如果这是C++,则使用new运算符。如果这是C,那么不要从void *转换为L值类型,它的风格很糟糕,可能会覆盖有用的编译器警告。

// Verify memory allocation. 
if (!data) 
{ 
    free(data); 

如果data为NULL,你不能释放它。

// Swap R and B because bitmaps are BGR and OpenGL uses RGB. 
for (unsigned int i = 0; i < dibheader.dataSize; i += 3) 
{ 
    B = data[i]; // Backup Blue. 
    data[i] = data[i + 2]; // Place red in right place. 
    data[i + 2] = B; // Place blue in right place. 
} 

OpenGL确实支持BGR对齐。格式参数是惊喜,GL_BGR

// Generate texture image. 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dibheader.width, dibheader.height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 

嗯,这错过设置像素存储参数的所有。在进行像素传输之前,始终设置每个像素存储参数,它们可能会保留在先前操作的某个不希望的状态。比对不起更安全。

+0

很久以前我试过GL_BGR,我只是得到一个未定义的错误。 无论哪种方式,我重写了加载程序,我将用新代码更新问题(并且不时发生其他错误)。 – zeluisping 2012-03-31 12:22:28

+0

@ 100GPing100:在OpenGL-1.1之后引入了GL_BGR,所以你需要一些扩展头来使用它。我建议GLEW,虽然只是那个标记,你不需要初始化所有的函数指针。 – datenwolf 2012-03-31 12:34:18

+0

我实际上使用了glew(在第一篇文章中说过)。 我是否需要从中“导入”类型? (就像在C#中,如果我们需要一个dll的函数,我们可以导入它) – zeluisping 2012-03-31 12:52:11