I am able to render the below points using the VBO and shaders in OpenGL 4.x.
typedef struct Point
{
double x,y,z,w;
}Point;
std::vector<Point>vPoints;
glBufferData(GL_ARRAY_BUFFER, vPoints.size()* sizeof(Point), &vPoints[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, vPoints.size()*sizeof(GLdouble), (GLvoid*)0)
How do we specify VBO to draw a line string using below variables
typedef struct LineString
{
vector<Point> vPointList;
}LineString;
vector<LineString> vLines;
glBufferData(GL_ARRAY_BUFFER, ????, ????, GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, ????, (GLvoid*)0)
I tried below setting and it does not seem to work
glBufferData(GL_ARRAY_BUFFER, vLines.size()* sizeof(LineString)*sizeof(Point), &vLines[0].vPointList[0], GL_STATIC_DRAW);
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, vLines.size()*sizeof(GLdouble), (GLvoid*)0);
I thought I almost got there with below code for VBO creation
for(int i=0;i< vLines.size();i++)
pt_count += vLines[i].vPointList.size();
fprintf( stdout, "Total point Count: %d\n", pt_count);
glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(Point), nullptr, GL_STATIC_DRAW);
size_t start = 0;
for(int i=0;i< vLines.size();i++)
{
size_t v_size =vLines[i].vPointList.size() * sizeof(Point);
glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &vLines[i].vPointList[0]);
start += v_size;
}
if(start == pt_count * sizeof(Point) )
{
fprintf( stdout, "INFO: %s\n", "Same count");
}
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, 4 * sizeof(GLdouble), (GLvoid*)0);
and drawing call.I noticed that the last point of first line is getting connected to first point of the line.
glDrawArrays(GL_LINE_STRIP, 0,pt_count);
glBufferData
For glBufferData, the total size of the data in bytes is required. In addition a consecutive memory segment is required, which a vector<vector<T>>
does not provide. Technically, each inner vector has it's own memory segment where the data is stored, which makes it impossible to upload the data at once. The only way that comes to my mind is to first calculate the total size like this:
size_t pt_count = 0;
for (auto& v : vLines)
pt_count += v.vPointList.size();
The allocate GPU memory, but without uploading any data
glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(Point), nullptr, GL_STATIC_DRAW);
The final step is then to upload all the points step by step:
size_t start = 0;
for (auto& v : vLines)
{
size_t v_size = v.vPointList.size() * sizeof(Point);
glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &v.vPointList[0]);
start += v_size;
}
But if you can change the data layout in the C++ code, I would strongly advice you to store all the points in a consecutive memory segment in the first place.
glVertexAttribPointer
The fifth parameter of glVertexAttribPointer tells OpenGL how much offset is between consecutive vertices in the buffer. So think of a buffer like this:
| x | y | z | w | x | y | z | w |
stride |-------------->|-------------->|
this is needed, since is is possible, that between two vertex entries additional data is stored. In your case, the offset has to be 4 * sizeof(GLdouble), or since the data is tightly packed, 0:
Specifies the byte offset between consecutive generic vertex attributes. If stride is 0, the generic vertex attributes are understood to be tightly packed in the array. The initial value is 0.
reference
Could solve this by making use of glMultiDrawArrays()..Found the solution by correctly specifying the index positions.The code looks like below after fixes.
//globals
size_t pt_count = 0;
GLint *startIndices;
GLint *endIndices;
GLint nLineCount;
//create the VBO
for(int i=0;i< vLines.size();i++)
pt_count += vLines[i].vPointList.size();
startIndices= new GLint[vLines.size()];
endIndices= new GLint[vLines.size()];
fprintf( stdout, "Total point Count: %d\n", pt_count);
glBufferData(GL_ARRAY_BUFFER, pt_count * sizeof(POINT), nullptr, GL_STATIC_DRAW);
size_t start = 0;
size_t firsts=0;
for(int i=0;i< vLines.size();i++)
{
size_t v_size =vLines[i].vPointList.size() * sizeof(POINT);
glBufferSubData(GL_ARRAY_BUFFER, start, v_size, &vLines[i].vPointList[0]);
start += v_size;
startIndices[i]=firsts;
endIndices[i]=vLines[i].vPointList.size();
firsts+=endIndices[i];
fprintf( stdout, "start: %d\n",startIndices[i]);
fprintf( stdout, "size: %d\n", endIndices[i] );
}
if(start == pt_count * sizeof(POINT) )
{
fprintf( stdout, "INFO: %s\n", "Same count");
}
glVertexAttribPointer(0, 4, GL_DOUBLE, GL_FALSE, 4 * sizeof(GLdouble), (GLvoid*)0);
nLineCount=vLines.size();
vLines.clear();
//Draw the lines
glMultiDrawArrays(GL_LINE_STRIP, startIndices,endIndices,nLineCount);