The clipboard routine worked in principle, but the image is inverted, like flipped around the horizontal axis.

Ah, I had too many false pictures yesterday and finally was happy that the colors appeared correctly with one set of parameters so that I did not look at the alignment. But it works correctly when you add the line

rawImg.Description.LineOrder := riloBottomToTop;

after

`rawImg.Description.Init_...` in "OpenGLToBitmap".

Now my remaining challenge is to try to get text on screen which I see is a bit of a headache but has to be done

Yes, drawing text by itself is not supported by OpenGL directly. Since you are on Windows you can use the routines in the attached "OpenGL_utils" units. The font routines work only on Windows; in other operating systems you'd have to access the fonts directly, for example by using the FreeType lib which comes with FPC/Laz - in this case the OpenGL support in TAChart could be helpful (units TAOpenGL and TAFonts).

But even when the fonts can be accessed the path to writing something into an OpenGL image still is stoney. I am attaching another modfied demo which shows how to write some 2D text into the 3D image. For this purpose OpenGL must temporarily be switched to an orthographic projection. The basic text out routine in the OpenGL_utils uses screen pixels (with the specialty that the y coordinate runs from bottom to top, not the other way as usual). In this mode you can add titles, legends or whatever (see procedure "DrawTitle")

An interesting case would be to attach the text to the drawing so that it follows the model when it is rotated, shifted or zoomed. An excample for the conversion from world coordinates to screen pixels is found in "DrawTextAtCubeCorners".

Note that the OpenGL system is in 2D mode when drawing this kind of text. Therefore labels are drawn even when the associated cube corner is not visible. I am sure that there is a way to fix this...

You can also draw the text in 3D mode (by using "Outline fonts" which give access to the individual nodes of the glyphs), but this requires a lot of additional work because the text can become almost illegible (upside down, mirrored) when the model is rotated.

and also drawing spheres which without glut seems to be involved as well.

I had to deal with spheres in a recent project and am adding the related procedure to the "OpenGL_Tools" as well. It creates the vertices on longitude and latitude circles and stores them in a "DisplayList" which is very useful because then the calculation of the vertices must be done only once. The calculated sphere has unit radius and sits in the origin. To give it the size required you must apply a Scaling operation ("glScalef(..)'), and a translation to move it to the desired location ("glTranslate(...)"). The way a lot of spheres can be drawn! Be careful to apply these operations in the right order - scale first, then translate. BUT: in OpenGL you write them in the opposite order - you must read OpenGL code from bottom upward! This is due to the way the transformation matrices are multiplied to the current overall transformation matrix.

glPushMatrix;

glTranslatef(x, 0, y); // Move sphere to correct place at x, y and z=0

glScalef(0.5, 0.5, 0.5); // Make radius = 0.5

glCallList(FSphereList); // use the stored sphere vertices from the displaylist

glPopMatrix;

The surrounding calls to "glPushMatrix" and "glPopMatrix" are needed to decouple these operations from the overal transformation matrix given by the mouse and mouse wheel opeations.

A further remark on DisplayLists: You should use them also to store the vertices of the polynomial surface to which you want to fit; this avoids recalculation of the vertices with every tiny mouse movement. And in particular, it avoids time-consuming calculation of the surface normal vectors. In case of a polynomial you can do this analytically, but for more general surfaces you can calculate the needed derivatives only numerically.

Spheres appear very simplistic when OpenGL does not use lighting. Therefore, the demo also shows how to "turn on the light". These are the essential ingredients: activate lights by calling "glEnable(GL_LIGHTING)", and define the parameters of one or several light sources (see "InitLight"). And every vertex must have a normal - for a sphere with r = 1 it is easy: it is just equal to the radius vector to a surface point. The surface normal is needed to calculate the angle to the light source which determines the brightness of each surface element due to diffuse or specular scattering of light.

In total: a lot to play with...

P.S.

The OpenGL_Tools contain also the corrected OpenGLToBitmap routine.