Dynamic control point array in gluNurbsSurface()

I have created a C++ OpenGL application (Windows XP, Visual Studio 2005) that renders terrain with NURBS surfaces. Everything works fine when I use a true array of control points with fixed dimensions but the app would be much more flexible if I could change the array dimensions at run time. I have been able to create arrays of pointers to simulate true arrays with square bracket indexing (I can read and write these ‘arrays’ just fine). I can also pass the ‘array’ to gluNurbsSurface() as an argument with no complaint from the compiler. When I use these ‘arrays’ at run time, no errors are reported by the error callback function. However, although gluNurbsSurface() takes about the same amount of time to ‘come back’ from processing the fake array as it does the real one, nothing appears to be rendered on the screen. Since gluNurbsSurface appears to be doing something, I’m guessing that it is getting confused by my pointers. I

Here’s some code to help explain the problem. If I do this, assuming I load the m_sample array with u, v, and height data:

GLfloat m_sample[200][200][3];
m_sample[u][v][0] = uval;
m_sample[u][v][1] = elevationVal;
m_sample[u][v][2] = vval;

gluNurbsSurface(m_theNurb, numberOfArbGridUKnots, uKnots, numberOfArbGridVKnots, vKnots, arbGridRows*3, 3, &m_sample[0][0][0]), ORDER, ORDER, GL_MAP2_VERTEX_3);

everything works ok and I see a rendered surface.

If I do this instead:

GLfloat ***m_sample;

and use allocate_3D to set it up (m_sample is in scope):

bool allocate_3D(int d1, int d2, int d3) {
if (m_sample!=0) {
return false;
}
m_sample=new GLfloat** [d1];
for (int i=0; i<d1; ++i) {
m_sample[i]=new GLfloat* [d2];
for (int j=0; j<d2; ++j) {
m_sample[i][j]=new GLfloat [d3];
for (int k=0; k<d3; ++k)
m_sample[i][j][k]=0;
}
}
return true;
}

then I can write my x,y,z data just as I could with the fixed array. But when I pass the dynamic version to gluNurbsSurface(), nothing appears to happen (no errors, but no rendered surface, either). Will gluNurbsSurface work with anything but a fixed array? Any other options? Any insights would be very welcome!

Jim

Dumb mistake on my part. I assumed that because the sample programs using gluNurbsSurface() were using 3D GLfloat arrays, that was how it had to be. Nope–just declare a linear pointer, fill it with the appropriate number of values at run time (cols * rows * 3) write in the u,v,elevation values for each, and let the stride values in the method call do the indexing. All is well now. Thanks for looking.

Jim

Hi there,

i got exactly the same problem over here. I tried to pass a dynamic C++ Vector to gluNurbsSurface(). But I get an exception thrown every time I start the allgorithm. I cant figure out why it’s not working. When I set the stride values to 0 the algortihm doesnt crash but no surface is shown (same as in the post above). My code is the following:

vector<vector<QVector3D>> tempPoints = CurvesModule_->getData(1);

		vector&lt;vector&lt;vector&lt;GLfloat&gt;&gt;&gt; controlpoints;
		vector&lt;GLfloat&gt; tempA;
		vector&lt;vector&lt;GLfloat&gt;&gt; tempB;

		for(int i=0 ; i&lt;tempPoints[0].size(); i++)//rows
		{
			for(int j=0 ; j&lt;tempPoints.size(); j++)//columns
			{
				tempA.push_back((GLfloat)tempPoints[j][i].x());
				tempA.push_back((GLfloat)tempPoints[j][i].y());
				tempA.push_back((GLfloat)tempPoints[j][i].z());
				tempB.push_back(tempA);
				tempA.clear();
			}
			controlpoints.push_back(tempB);
			tempB.clear();
		}

		GLUnurbsObj *theNurb;

		theNurb = gluNewNurbsRenderer();
		gluNurbsProperty(theNurb, GLU_SAMPLING_TOLERANCE, 25);
		gluNurbsProperty(theNurb, GLU_DISPLAY_MODE, GLU_FILL);//GLU_FILL  GLU_OUTLINE_POLYGON

		//Define knot vectors - NOTICE that there were (degree+1) controlpoints addded as thershold
		vector&lt;double&gt; tempknota =  CurvesModule_-&gt;getKnotVector(1);
		vector&lt;GLfloat&gt; knotT;
		for(int i=0 ; i&lt;tempknota.size(); i++)
			knotT.push_back((GLfloat)tempknota[i]);
	
		vector&lt;double&gt; tempknotb = CurvesModule_-&gt;getKnotVector(0);
		vector&lt;GLfloat&gt; knotS;
		for(int i=0 ; i&lt;tempknotb.size(); i++)	
			knotS.push_back((GLfloat)tempknotb[i]);

		gluBeginSurface(theNurb);
		gluNurbsSurface(theNurb, knotT.size(), 
			&knotT[0], knotS.size(), &knotS[0],
			(knotS.size() - degree - 1) * sizeof(GLfloat) * 3, 3 * sizeof(GLfloat), &controlpoints[0][0][0],
			degree+1, degree+1, GL_MAP2_VERTEX_3);
		gluEndSurface(theNurb);

I hope somebody can give me a hand with this.


vector<vector<GLfloat>>

I haven’t read your whole post, but from what I’ve seen it looks like you assume the above gives you one contiguous chunk of memory - it does not.
A single std::vector is guaranteed to allocate a single contiguous block of memory - note: it allocates a block, it does not contain the block, in fact a std::vector usually contains only three pointers (start, end, capacity_end) to the allocated storage. So placing a std::vector inside another one one makes those pointers lay next to each other in memory, but the chunks they point to are scattered across the free store.

ok i see that now. I tried to define a 1D array, put all my controlpoints in there and let the stride values to the indexing. It’s still not working. Fo that I assumed that a 3D array ist basically just 1D array with only the last dimension beeing linear. Is that correct? My code snippet:

vector<vector<QVector3D>> tempPoints = CurvesModule_->getData(1);
GLfloat* controlpoints = new GLfloat[tempPoints.size()*tempPoints[0].size()*3];

		for(int i=0 ; i&lt;tempPoints.size(); i++)
		{
			for(int j=0 ; j&lt;tempPoints[0].size(); j++)
			{
				controlpoints[(i*tempPoints[0].size())+(j*3)+0] = tempPoints[i][j].x();
				controlpoints[(i*tempPoints[0].size())+(j*3)+1] = tempPoints[i][j].y();
				controlpoints[(i*tempPoints[0].size())+(j*3)+2] = tempPoints[i][j].z();
			}
		}

and

gluNurbsSurface(theNurb, tempknotS.size(),
&knotS[0], tempknotT.size(), &knotT[0],
tempPoints[0].size()*3, 3, &controlpoints[0],
degree+1, degree+1, GL_MAP2_VERTEX_3);

By the way what is a linear pointer? Is it a pointer referencing to another pointer? I googled it but couldnt find a thing about it.

Please use [ code]/[ /code] (no space after ‘[’) around code snippets to make them easier to read, thanks.


controlpoints[(i*tempPoints[0].size())+(j*3)+0] = tempPoints[i][j].x();

is tempPoints[0].size() == tempPoints[1].size(), if not that is where your indexing goes wrong (also in the upper bound of the inner loop).

By the way what is a linear pointer?

No idea.

The expression tempPoints[0].size() == tempPoints[1].size() is true. They all have the same size.