Как я могу использовать массив текстур динамического размера с glTexImage2D? - PullRequest
3 голосов
/ 24 марта 2009

В настоящее время я могу загрузить текстуру статического размера, которую я создал. В данном случае это 512 х 512.

Этот код из шапки:

#define TEXTURE_WIDTH 512
#define TEXTURE_HEIGHT 512

GLubyte textureArray[TEXTURE_HEIGHT][TEXTURE_WIDTH][4];

Вот использование glTexImage2D:

glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    TEXTURE_WIDTH, TEXTURE_HEIGHT,
    0, GL_RGBA, GL_UNSIGNED_BYTE, textureArray);

А вот как я заполняю массив (грубый пример, не точная копия из моего кода):

for (int i = 0; i < getTexturePixelCount(); i++)
{
    textureArray[column][row][0] = (GLubyte)pixelValue1;
    textureArray[column][row][1] = (GLubyte)pixelValue2;
    textureArray[column][row][2] = (GLubyte)pixelValue3;
    textureArray[column][row][3] = (GLubyte)pixelValue4;
}

Как мне изменить это так, чтобы не было необходимости в TEXTURE_WIDTH и TEXTURE_HEIGHT? Возможно, я мог бы использовать массив стилей указателя и динамически распределять память ...

Edit:

Я думаю, что вижу проблему, в C ++ это не может быть сделано. Обходной путь, как указал Будрик, заключается в использовании одномерного массива, но с использованием всех трех измерений, умноженных для представления индексов:

GLbyte *array = new GLbyte[xMax * yMax * zMax];

А чтобы получить доступ, например, к x / y / z 1/2/3, вам нужно сделать:

GLbyte byte = array[1 * 2 * 3];

Однако проблема в том, что я не думаю, что функция glTexImage2D поддерживает это. Может кто-нибудь придумать обходной путь, который будет работать с этой функцией OpenGL?

Редактировать 2:

Внимание разработчиков OpenGL, это можно преодолеть, используя одномерный массив пикселей ...

[0]: столбец 0> [1]: строка 0> [2]: канал 0 ... n> [n]: строка 1 ... n> [n]: столбец 1 .. n

... нет необходимости использовать трехмерный массив. В этом случае мне пришлось использовать эту работу, так как 3-мерные массивы, очевидно, не являются строго возможными в C ++.

Ответы [ 3 ]

5 голосов
/ 30 января 2012

Хорошо, так как мне понадобилось много времени, чтобы понять это, вот оно:

Моей задачей было реализовать пример из Красной книги OpenGL (9-1, p373, 5-е издание) с динамическим массивом текстур.

В примере используется:

static GLubyte checkImage[checkImageHeight][checkImageWidth][4];

Попытка выделить 3-мерный массив, как вы можете догадаться, не сработает. Someth. как это делает НЕ работа:

GLubyte***checkImage;
checkImage = new GLubyte**[HEIGHT];

for (int i = 0; i < HEIGHT; ++i)
{
  checkImage[i] = new GLubyte*[WIDTH];

  for (int j = 0; j < WIDTH; ++j)
    checkImage[i][j] = new GLubyte[DEPTH];
}

Вы должны использовать одномерный массив :

unsigned int depth = 4;

GLubyte *checkImage = new GLubyte[height * width * depth];

Вы можете получить доступ к элементам, используя следующие циклы:

for(unsigned int ix = 0; ix < height; ++ix)
{
  for(unsigned int iy = 0; iy < width; ++iy)
  {
    int c = (((ix&0x8) == 0) ^ ((iy&0x8)) == 0) * 255;

    checkImage[ix * width * depth + iy * depth + 0] = c;   //red
    checkImage[ix * width * depth + iy * depth + 1] = c;   //green
    checkImage[ix * width * depth + iy * depth + 2] = c;   //blue
    checkImage[ix * width * depth + iy * depth + 3] = 255; //alpha
  }
}

Не забудьте удалить его правильно:

delete [] checkImage;

Надеюсь, это поможет ...

4 голосов
/ 25 марта 2009

Вы можете использовать

int width = 1024;
int height = 1024;
GLubyte * texture = new GLubyte[4*width*height];
...
glTexImage2D(
    GL_TEXTURE_2D, 0, GL_RGBA,
    width, height,
    0, GL_RGBA, GL_UNSIGNED_BYTE, textureArray);
delete [] texture;         //remove the un-needed local copy of the texture;

Однако вам все равно нужно указать ширину и высоту для OpenGL в вызове glTexImage2D. Этот вызов копирует данные текстуры, и эти данные управляются OpenGL. Вы можете удалять, изменять размеры, изменять исходный массив текстур, сколько хотите, и он не будет отличаться от текстуры, которую вы указали для OpenGL.

Edit: C / C ++ имеет дело только с одномерными массивами. Тот факт, что вы можете сделать текстуру [a] [b], скрыт и конвертируется компилятором во время компиляции. Компилятор должен знать количество столбцов и будет делать текстуру [a * cols + b].

Используйте класс, чтобы скрыть выделение, доступ к текстуре.

В академических целях, если вам действительно нужны динамические многомерные массивы, должно работать следующее:

int rows = 16, cols = 16;
char * storage = new char[rows * cols];
char ** accessor2D = new char *[rows];
for (int i = 0; i < rows; i++)
{
    accessor2D[i] = storage + i*cols;
}
accessor2D[5][5] = 2;
assert(storage[5*cols + 5] == accessor2D[5][5]);
delete [] accessor2D;
delete [] storage;

Обратите внимание, что во всех случаях я использую одномерные массивы. Это просто массивы указателей и массив указателей на указатели. Это накладные расходы на память. Также это сделано для 2D массива без цветовых компонентов. Для разыменования 3D это становится действительно грязным. Не используйте это в своем коде.

1 голос
/ 25 марта 2009

Вы всегда можете обернуть это в классе. Если вы загружаете изображение из файла, вы получаете высоту и ширину вместе с остальными данными (как еще вы можете использовать файл?), Вы можете сохранить их в классе, который оборачивает загрузку файла, вместо использования препроцессора, определяемого , Что-то вроде:

class ImageLoader
{
...
  ImageLoader(const char* filename, ...);
...
  int GetHeight();
  int GetWidth();
  void* GetDataPointer();
...
};

Еще лучше, если бы вы могли скрыть вызовы функций для glTexImage2d там с ним.

class GLImageLoader
{
...
  ImageLoader(const char* filename, ...);
...
  GLuint LoadToTexture2D(); // returns texture id
...
};
...