2012-03-30 5 views
1

Я пишу приложение с использованием OpenGL (freeglut и glew).C++ OpenGL glTexImage2D Нарушение прав доступа

Мне также нужны текстуры, поэтому я провел некоторое исследование формата файла битмапа и написал структуру для основного заголовка, а другую для заголовка DIB (заголовок info).

Затем я начал писать загрузчик. Он автоматически связывает текстуру с 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] 

Это не ошибка с моим загрузчиком, потому что я загрузил другие загрузчики. Загруженный загрузчик, который я использовал, был this one от NeHe.

EDIT: (КОД ОБНОВЛЕНО ВЫШЕ)

я переписал загрузчик, но я все еще получаю аварию на одной и той же линии. Вместо этого аварии, иногда я получаю аварии на 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

+0

Это больше похоже на C, чем на C++ – Pubby

+0

@ktodisco. Размер данных на самом деле правильный. – zeluisping

ответ

2

Я знаю, это заманчиво читать двоичные данные, как этот

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

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

но вы действительно не должны делать это таким образом. Зачем? Поскольку макет памяти структур может быть дополнен для соответствия ограничениям выравнивания (да, я знаю, что касается упаковки прагм), размер типа используемого компилятора может не соответствовать размеру данных в двоичном файле, и последнее, но не менее важное, ,

Всегда читайте двоичные данные в промежуточный буфер, из которого вы извлекаете поля четко определенным образом с точно указанными смещениями и типизацией.

// 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

+0

@ 100GPing100: GL_BGR был представлен после OpenGL-1.1, поэтому вам нужен заголовок расширения, чтобы использовать его. Я рекомендую GLEW, хотя для этого же токена вам не нужно инициализировать все указатели на функции. – datenwolf

+0

Я использую glew на самом деле (говорится в первом сообщении). Нужно ли мне «импортировать» типы из него? (например, в C#, если нам нужна функция из dll, мы можем ее импортировать) – zeluisping

6

Попробуйте glPixelStorei(GL_UNPACK_ALIGNMENT, 1) до вашего glTexImage2D() вызова.

+0

Я забыл упомянуть, что я уже это пробовал. Изображение - 24bpp 512x512. Он падает с той же ошибкой (просто попробовал еще раз). – zeluisping