I have a graphics object which I call Component (a C++ class). Just to
be concrete and clear I'll give the detail that Componet has the
following data members:
private:
std::string name_;
Type t_;
GLfloat matrix_[16];
GLfloat mSpecular_[4], mAmbient_[4], mDiffuse_[4],
mEmission_[4], mShininess_;
GLUquadricObj *q_;
GLfloat r1_, r2_, len_;
int sl_, st_; // slices, stacks
};
In the constructor, I /previously/ had:
// A1
q_ = gluNewQuadric();
gluQuadricDrawStyle(q_, GLU_FILL);
gluQuadricNormals(q_, GLU_SMOOTH);
The quadric was only ever deleted in the ~Component destructor, and that
was only ever called when the program terminated execution.
I had a time triggered 'update'. Then I had a 'draw' which had:
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mSpecular_);
// etc.
// A2
gluCylinder(q_, r1_, r2_, len_, sl_, st_);
and this 'draw' gets called about 50 times a second in an animation
loop. The only variables that change during the animation are rotation
angles and translations.
The problem:
Sometimes the quadric appeared and sometimes not --- same executable;
sometimes it disappeared during the execution, all quite randomly.
The solution that I have now is to have no mention of the quadric in the
constructor and to have
// B2
q_ = gluNewQuadric();
gluQuadricDrawStyle(q_, GLU_FILL);
gluQuadricNormals(q_, GLU_SMOOTH);
gluCylinder(q_, r1_, r2_, len_, sl_, st_);
gluDeleteQuadric(q_);
in 'draw'.
Any ideas on why the scheme in // A1, A2 fails (randomly) to show the
quadric.
I wonder is the scheme in // B2 rather inefficient? It 'works', but I
don't want to expose really bad practice in a teaching example.
I /may/ be able to put gluCylinder(q_, r1_, r2_, len_, sl_, st_); in a
display list, but it would be nice to retain the possibility of the
dimensions changing.
TIA,
Jon C.
--
Jonathan Campbell www.jgcampbell.com BT48, UK.
Whenever you see "random" in C++, think "uninitialized variable".
--
<\___/>
/ O O \
\_____/ FTB.
http://www.topaz3d.com/ - New 3D editor for real time simulation
I totally agree.
I've done a prolonged series of experiments ... use ColorMaterial ...
then disable lighting and use plain Color ... create my own object
(instead of a quadric).
The only common factor seems to be my previous use of the quadric and I
cannot see what is uninitialised there.
Would it be normal to place code like this in a 'draw' that gets
executed every frame in an animation? This is what 'works'.
q_ = gluNewQuadric();
gluQuadricDrawStyle(q_, GLU_FILL);
gluQuadricNormals(q_, GLU_SMOOTH);
gluCylinder(q_, r1_, r2_, len_, sl_, st_);
gluDeleteQuadric(q_);
I'd have thought that placing
q_ = gluNewQuadric();
gluQuadricDrawStyle(q_, GLU_FILL);
gluQuadricNormals(q_, GLU_SMOOTH);
in a called-once only initialisation and then
gluCylinder(q_, r1_, r2_, len_, sl_, st_);
in the 'draw' would be more sensible, but it is that which exhibits the
random behaviour.
Best regards,
Obviously it will be slower, the only question is "how much?"
> I'd have thought that placing
>
> q_ = gluNewQuadric();
> gluQuadricDrawStyle(q_, GLU_FILL);
> gluQuadricNormals(q_, GLU_SMOOTH);
>
> in a called-once only initialisation and then
>
> gluCylinder(q_, r1_, r2_, len_, sl_, st_);
>
> in the 'draw' would be more sensible, but it is that which exhibits the
> random behaviour.
>
You might be doing something bad in another part of
your program. Try writing a minimal program which does
only this, nothing more.
... and for detecting uninitialized variables/structure fields/anything,
valgrind is an amazingly useful (and just generally amazing) tool.
Even if your program doesn't appear to have any bugs, it's good practice
to run it under valgrind occasionally -- it's very likely it will find
something.
-miles
--
"... The revolution will be no re-run brothers; The revolution will be live."
Yes, damned amazing! Though I despaired at having to read a manual, the
output gave me enough to narrow my suspicions.
> Even if your program doesn't appear to have any bugs, it's good practice
> to run it under valgrind occasionally -- it's very likely it will find
> something.
>
Bingo, I think I have it.
class Component{
...
private:
std::string name_;
Type t_;
GLfloat matrix_[16];
GLfloat mSpecular_[4], mAmbient_[4], mDiffuse_[4],
mEmission_[4], mShininess_;
GLUquadricObj *q_;
GLfloat r1_, r2_, len_;
int sl_, st_; // slices, stacks
};
Component::Component(){
...
setMAmbient(grey6);
setMShininess(30.0);
q_ = gluNewQuadric();
gluQuadricDrawStyle(q_, GLU_FILL);
gluQuadricNormals(q_, GLU_SMOOTH);
r1_ = r2_ = 1.0f;
len_ = 2.0f;
sl_ = st_ = 10;
}
Then in the class (Scene) that uses Component
comp = Component();
thereby invoking the constructor immediately followed by the assignment
operator, which is the default compiler-supplied one, i.e. 'q_' get
copied, but not what it points to, and what it points to gets destroyed
immediately after the copy/assign.
The following seems to correct the problem:
Scene() : comp(Component()){
though I guess I should disable the assignment operator by making it
private.
So it was an uninitialised variable! Oh dear.
And apologies for the incompetent debugger's lament "but it cannot be ...".
Very many thanks,
BTW, to people who may wish to use valgrind in a Linux/g++ environment,
I think you need to ask g++ to generate debugging information in order
to get source line numbers in diagnostics, i.e.
g++ -g -W -Wall -ansi -pedantic ...
... gets destroyed by the destructor acting on the temporary, that is.
J.C.