указатель на `std::list` собственных данных

Я использую 2-мерный вектор Eigen3 в качестве 2D-точки для рисования opengl, сохраняя их в списке:

typedef Eigen::Vector2d Vec2D;
std::list<Vec2D> points;

Теперь мне нужен массив GLfloat для передачи всей структуры данных исходного значения координат с плавающей запятой на графическую карту:

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

_vertex = new GLfloat[points.size()*2];
_colors = new GLfloat[points.size()*4];

std::list<Vec2D>::const_iterator it;
int i=0, j=0;
for(it=points.begin(); it!=points.end(); ++it) {
    _vertex[i] = it->x()+2;
    _vertex[i+1] = it->y()+2;
    i+=2;

    _colors[j] = getRed(j/4.0f, it);
    _colors[j+1] = getGreen(j/4.0f, it);
    _colors[j+2] = getBlue(j/4.0f, it);
    _colors[j+3] = getAlpha(j/4.0f, it);
    j+=4;
}

glColorPointer(4, GL_FLOAT, 0, _colors);
glVertexPointer(2, GL_FLOAT, 0, _vertex);
glDrawArrays(GL_LINE_STRIP, 0, points.size());

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);

delete _vertex;
delete _colors;

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

Я имею в виду ... в памяти координаты x и y Eigen::Vector2d должны храниться в некотором последовательном пространстве ... так что ... я думаю, что могу передать их непосредственно на графическую карту ... но я не могу понять, как это сделать.


person nkint    schedule 29.06.2013    source источник
comment
Вам нужен собственный буфер gl?   -  person huseyin tugrul buyukisik    schedule 29.06.2013
comment
что извините? Мне нужно - из документации opengl glVertexPointer: указатель на первую координату первой вершины в массиве.   -  person nkint    schedule 29.06.2013
comment
Я также изменил название ответа, надеюсь, немного понятнее   -  person nkint    schedule 29.06.2013


Ответы (2)


std::list не хранит данные в непрерывной памяти, для этого вам нужен std::vector (или std::array, если вы знаете размер во время компиляции, но вы, вероятно, этого не знаете). Vector имеет метод data(), который возвращает указатель на базовые данные. Однако, если вы храните Eigen::vec2d внутри, вы не можете передать его в openGl, так как это динамическая структура, и ваши данные будут находиться во всей вашей памяти. Вам нужна структура, которая удерживает данные на месте (кстати, она более удобочитаема, чем vec2d, что довольно странно в данном контексте). Например:

struct VertexData
{
    GLfloat x;
    GLfloat y;
    GLfloat red;
    GLfloat green;
    GLfloat blue;
    GLfloat alpha;    
}

А затем используйте glVertexPointer, чтобы передать его в openGL, используя sizeof(VertexData) как шаг

Чтобы удалить новые массивы, вам нужно использовать

delete [] _vertex;

нормальное удаление освободит только первый элемент. Или, что еще лучше, вы можете использовать интеллектуальные указатели, в этом случае лучше всего подойдет std::unique_ptr.

std::unique_ptr<GLfloat[]> _vertex(new GLfloat[points.size() * sizeof(GLfloat)]);

Он автоматически освобождает память, когда она выходит за рамки (в конце блока).

person aryan    schedule 29.06.2013
comment
Спасибо за твой ответ. но .. можете ли вы предоставить мне минимальный фрагмент примера для интеллектуального указателя или удаления? а как насчет собственной памяти? Я думаю, что у Vec2D probb есть некоторые недостатки.. как это узнать? - person nkint; 29.06.2013
comment
Возможно sizeof(Vec2D)!=2*sizeof(GLfloat) действительно. Вы можете проверить это с помощью cout. Если это так, вам нужно будет использовать sizeof(Vec2D) вместо stride в вызовах gl, иначе даже с .data() это не сработает. - person Yohan Danvin; 29.06.2013
comment
Vec2D, вероятно, является динамическим, и поэтому вы не можете просто передать их в ogl. я отредактировал свой ответ - person aryan; 29.06.2013
comment
Vec2D основан на векторах Eigen3, где все основано на параметрах шаблона. Так что не динамический (если под этим вы подразумеваете атрибуты указателя). С offset и stride должно работать нормально. - person Yohan Danvin; 29.06.2013
comment
Я проверил документы Eigen, и vector2d — это просто забавный способ сказать «пара двойников». Таким образом, вы можете использовать его с glVertexPointer, но я думаю, что пользовательская структура лучше выдаст ваши намерения. - person aryan; 29.06.2013
comment
как я могу проверить это? Я имею в виду, как я могу написать функцию с тем же API glTest(num_data_to_read, type, stride, raw_array);? только с приращением указателя type *it = raw_array; ... it+=sizeof(stride) ? - person nkint; 30.06.2013

points — это std::list, поэтому он не содержит непрерывного массива данных.

Однако, если вместо этого вы используете std::vector, то в С++ 11 вы можете получить доступ к массиву, используемому внутри, с помощью points.data(). Это означает, что вам больше не нужен _vertex.

Знайте, что в качестве альтернативы вы можете даже пойти дальше и создать класс (названный, например, Vertex), который содержит как позицию вершины, так и ее цвет, а затем использовать метод data() для вашего std::vector<Vertex> в сочетании с glInterleavedArraysstride=sizeof(Vertex)).

person Yohan Danvin    schedule 29.06.2013
comment
почему не glDrawArrays? Это также позволяет мне указать смещение/шаг. Antway, спасибо. Ваш голос должен использовать пользовательскую структуру вместо Eigen::vector2d.. - person nkint; 29.06.2013
comment
Да, вы можете добиться того же с помощью нескольких вызовов glDrawArrays, но я не хотел вдаваться в подробности, чтобы не усложнять ответ. :) Честно говоря, пользовательская структура или нет, это действительно зависит от того, что вы хотите сделать с цветами здесь. Однако постарайтесь так или иначе избавиться от new/delete в своем коде, как сказал aryjczyk. В вашем примере вы могли бы, например, ввести 2 массива _.. как std::vector<GLfloat> или std::unique_ptr<GLfloat[]> вместо необработанных указателей GLfloat*. - person Yohan Danvin; 29.06.2013