I think that we must translate (invert) the camera pos

What you call "// Convert to OpenGL matrix notation" in your GL_BillBoard() is in fact the so called "matrix transpose", i.e. getting the inverse of current modelview (rotation) matrix. Multiplying the current matrix by its (transposed) inverse in the

**glMultMatrixf(&mm[0])** (in fact, glMultMatrixf(mm) in C notation) yields effectively an un-rotated identity modelview matrix with all of its three rotation angles reset to 0. At the same time, its translation/scaling components as set by gluLookAt() remain intact, and that is why the ONYX plate stays well sized and zoomable but glued to the same point of projection onto the screen plane -- in other words, doesn't follow the model's general rotation pattern any more.

This is sufficient for an FPS camera (pun not intended; FPS here means "first-person shooter") that moves relative to the static model, but it isn't, for an orbiting camera like in ObjReader that stays put at the world's [0,0,0] while the model is dragged/rotated following mouse movements.

So, for what it's worth GL_BillBoard() takes us only halfway through to our goal in ObjReader. We must go further and move the billboard quad to a correct point in the 2D screen space and also project it correctly to emulate its X rotation (cylindrical a.k.a. Y axis-aligned billboard -- "tree-like"), X/Y rotation (spherical billboard -- "particle-like"), or leave it as-is without projection distortion (HUD a.k.a. "text-like" billboard).

All manual transformations are highly dependent on the order of glTranslate, glScale and glRotate calls, and also on the methods of obtaining pitch/yaw/roll angles in response to mouse dragging.

These are the issues with the billboard problem we're currently facing in ObjReader.