Как я могу использовать массив текстур динамического размера с glTexImage2D?
В настоящее время я могу загрузить текстуру статического размера, которую я создал. В этом случае это 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? Возможно, я мог бы использовать массив стилей указателя и динамически распределять память...
Редактировать:
Я думаю, что вижу проблему, в C++ это не может быть сделано. Обходной путь, на который указывает Budric, заключается в использовании одномерного массива, но с использованием всех трех измерений, умноженных для представления индексов:
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 ответа
Ты можешь использовать
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.
Изменить: 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 это становится действительно грязным. Не используйте это в своем коде.
Хорошо, так как это заняло у меня много времени, чтобы понять это, вот оно:
Моей задачей было реализовать пример из Красной книги OpenGL (9-1, p373, 5th Ed.) С динамическим массивом текстур.
В примере используются:
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;
Надеюсь это поможет...
Вы всегда можете обернуть это в классе. Если вы загружаете изображение из файла, вы получаете высоту и ширину вместе с остальными данными (как еще вы можете использовать файл?), Вы можете сохранить их в классе, который оборачивает загрузку файла, вместо использования препроцессора, определяемого, Что-то вроде:
class ImageLoader
{
...
ImageLoader(const char* filename, ...);
...
int GetHeight();
int GetWidth();
void* GetDataPointer();
...
};
Еще лучше, если бы вы могли скрыть вызовы функций для glTexImage2d там с ним.
class GLImageLoader
{
...
ImageLoader(const char* filename, ...);
...
GLuint LoadToTexture2D(); // returns texture id
...
};