Higher C++ interface for OpenGL

I’m thinking on creating a basic but higher interface for OpenGl in C++. The main idea is
to handle the OpenGL context and calls as
a stream, so one could write something like
gl::rc << gl::begin(gl::POINTS)
<< p << q << gl::end;
where say p,q points that overload the
<< operator

My question is if any of you knows there is something like that already (and is open source) ?

foo(bar, x, y, z);

hmmm…, we need something higher…

bar->foo(x, y, z);

Good! But we can get higher than that…

fubar << foo(bar, x, y, z);

Great!! But why stop now? Let’s go even HIGHER!!

fubar << foo << bar << x << y << z;

AWESOME!!!
Now that’s a higher C++ interface for OpenGL \o/ !!

[This message has been edited by 3k0j (edited 12-19-2003).]

Ok my example is lame, but if I had worked
all the details out, I wouldn’t need to post
right?
Something like…

template< typename T, class Stream >
somedrawfunc(Stream out)
{

Container< Point > &points;
out << “Here are the points” << points;

}
and then something like
gl::RCstream rc(dc);
gl: Lstream< RCstream > list(rc);
gl::CSstream< RCstream > clien(rc);

somedrawfunc< float >(rc);
somedrawfunc< double >(list);
somedrawfunc< mpz_class >(clien);
somedrawfunc< int >( std::cout );
somedrawfunc< int >( std::fstream(“point.bmp”));

and yes << could be syntactic sugar but it
makes more sense to me at least like that…

I’m working on something similar. I’m calling it “Ozone”.

Object-Oriented OpenGL -> O^3 -> Ozone.
If I get permission from the employer, I’d like to open source it.

You might want to check out XEngine, too.

-Won

But… why?!?

Isn’t your energy better spent writing useful and cool applications with the existing C interface, rather than trying to write ugly and contrived C++ wrappers that no sane person will want to use?

– Tom

This is a good point. It is very difficult to write a C++ wrapper that doesn’t somehow sacrifice performance or readability.

So what’s the point?

First of all, I DO plan on using my own wrapper, otherwise why would I bother?

Second, to say that it is merely a “contrivance” tacitly denies the possibility that a wrapper can improve productivity/code legibility etc. Quite the presumption. There are many benefits to having that extra layer of indirection.

Third, immediate mode is something of an abomination, anyway. I wouldn’t really bother too much wrapping that in C++; it would be more for the object-oriented aspects of OpenGL that are crippled with a C-like interface.

Obviously, the wrapper won’t be as familiar as straight-up OpenGL code, but I’m hoping the advantages will outweigh this disadvantage enough that someone besides the authors will use it.

-Won

In general, the only place I’ve found an OO wrapper useful in OpenGL is for managing the lifespan of “objects”. Specifically texture objects, display lists, and program objects.

And with those, I would probably do it differently today than I did then.

The class of code that I have found very useful to keep is for doing things that OpenGL doesn’t do for you, like linear algebra and object interaction. It would be really great if OpenGL included more support in this arena (via a major GLU update or another standard companion library). OpenGL does not compete well with D3D in this regard, and it is a barrier to entry for OpenGL developers.

Thanks -
Cass

Something like…

Well, that has to be the worst interface for drawing triangles imaginable. Not only does it put horrific overhead in a performance-critical section of code, it reduces the readability of that section of code by an order-of-magnitude. Additionally, it continues the poor C++ paradigm of overloading the bitshift operator for non-bitshift tasks.

Second, to say that it is merely a “contrivance” tacitly denies the possibility that a wrapper can improve productivity/code legibility etc. Quite the presumption. There are many benefits to having that extra layer of indirection.

Such as? Besides slowing down performance-critical sections of code?

Third, immediate mode is something of an abomination, anyway. I wouldn’t really bother too much wrapping that in C++; it would be more for the object-oriented aspects of OpenGL that are crippled with a C-like interface.

You don’t have the ability to “un-cripple” them. The way to uncripple them would be to have functions that, effectively, took an object as a parameter. However, the OpenGL interface doesn’t take the object as a parameter, so you have to keep re-binding the object each time you want to call a function. I don’t know what kind of penalty object binding costs, but I can’t imagine that it is cheap in all cases. At which point, once again, you’re dropping performance in performance-critical sections of code.

[This message has been edited by Korval (edited 12-19-2003).]

Just to make myself clear: I think that putting a thin C++ wrapper around the GL is a complete waste of time. Especially if it looks as ugly as what you’re proposing.

But I’m not at all opposed to the idea of having, say, a reusable texture class. You could add in some functionality to load images from disk, or you could have separate classes for disk-based textures and dynamically rendered textures, and share some code between them through inheritance. Similarly, encapsulating shaders or vertex arrays in classes might facilitate writing multiple code paths for different HW. Nobody will argue with you if you do any of this. I wouldn’t call this a “C++ interface for OpenGL” or a “wrapper” anymore though.

– Tom

I think that the fact that OpenGL is an absolutely not object oriented state machine thing is a pain a lot of times, when you are trying to write a rather large application with a neat class structure that uses OpenGL. Keeping track of “which objects need which OpenGL states in which condition and where are all these states at the moment one certain object is called to render itself” is a chaos, again and again. So a clear object oriented solution to this would be a good thing (and again, it would not have to wrap time critical code pars like the stuff that happens between glBegin() and glEnd() ), but also probably impossible when not using something like a scene graph.

well… something i’ve written once wich was rather useful was a glDraw routine, wich worked like this:

glDraw(GL_POINTS) {
glVertex3f(…);
glVertex3f(…);
}

wich wrapped glBegin/glEnd… i’ve continued this, to wrap other stuff into {}.

this was essencially useful during the time i got hardlocks if i forgot a glEnd somewhere… that way my compiler took care of the lifetime of different gl-states. if i forgot to glEnd, i got a compiler error that i miss a }…

that is at least useful. making gl errors language errors => compiler errors. much more easy to catch the bug (compared to bluescreen and restarting, for sure )

btw, i like the stream-idea, at least sort of… you could get me to reinstall vc again, just for the fun of c++ hacking for funny interfaces

i could do it in D, too… then again, the {} hack isn’t possible there… or… hm… we’ll see

why to do something like that? because its fun… and it can make your code more rapit, less to type, more save, and you can move runtime errors to compile-time errors. something VERY useful imho. c++ is an awesome language to “teach the compiler opengl” . is it a hack? yes. is it useful? well… yes it helps but it would need to go into the next c++ standard (including opengl) to get widely addapted…

but that would be cool… std::gl

Funny how people equate OO design to “lots of dereference operators”

glBindTexture

There’s your OOD. A texture object encapsulates and hides implementation details, it has defined behaviour. The only thing missing is the dereference operator and there are reasons for that.

You’ll never see “this pointers”, you’ll see object names. It’s the only way to guarantee fail-safe behaviour, and separate namespaces for different types of objects.

A robust GL implementation must be able to maintain sparsely populated arrays of names over the whole integer range. Finding the actual pointer to the implementation details and state belonging to the named object takes time.

If nothing else, object selection reduces function call overhead as soon as you use the bound object more than once in a row (where “use” includes changing object properties, eg glTexParameteri).

PS:
C bindings are portable. C++ bindings aren’t even portable between different compilers on the same platform.

//Object-based
glTexParameteri(texObj, Params);
glTexParameterf(texObj, OtherParams);

/vs. state-based
glBindTexture(texObj);
glTexParameteri(Params);
glTexParameterf(OtherParams);

Seems to me that the state-based approach required 3 function calls, and thus has more overhead than just 2. Granted, you’re not passing as many parameters, but you’ve potentially blown the instruction cache by going to an entirely different function in the glBind* case.

C bindings are portable. C++ bindings aren’t even portable between different compilers on the same platform.

I don’t think anyone is asking that OpenGL be made as a C++ API.

[This message has been edited by Korval (edited 12-19-2003).]

Originally posted by Korval:

[quote]

//Object-based
glTexParameteri(texObj, Params);
glTexParameterf(texObj, OtherParams);

/vs. state-based
glBindTexture(texObj);
glTexParameteri(Params);
glTexParameterf(OtherParams);

Seems to me that the state-based approach required 3 function calls, and thus has more overhead than just 2. Granted, you’re not passing as many parameters, but you’ve potentially blown the instruction cache by going to an entirely different function in the glBind* case.[/QUOTE]Somewhat agreed. You forgot the targets, but that in fact makes the following easier
The point I was trying to make is that the “object based” approach requires other functions to do name to object lookups, or object creation.

Somewhat optimized version:

//internal texture objects
std::map <GLuint,Texture*> texture_container; 

//cache last object for quick reuse
GLuint current_tex_name=0;
Texture* current_tex_pointer=&default_texture_object;

void
glTexParameteri(GLuint tex_name,GLenum params)
{
   //potential redundancy starts here :-)
   if (tex_name!=current_tex_name)
   {
      //find internal data in container
      //this is potentially very slow
      texture_container.find(<...> );
      ...
      if (not_found)
      {
         current_tex_pointer=create_new_object();
         add_it_to_container_as(tex_name);
      }
      else
      {
         current_tex_pointer=what_we_found;
      }
      current_tex_name=tex_name;
   }
   //actually do something
   current_tex_pointer->apply_stuff(params);
}

You’d end up doing something like that for all functions acting on texture objects. So by your own argument, to preserve code cache (and branch predictor resources …), it would IMO be preferable to have this:

void
glBindTexture(GLuint tex_name)
{
if (tex_name!=current_tex_name)
{
//find internal data in container
//this is potentially very slow
texture_container.find(<…> );

if (not_found)
{
current_tex_pointer=create_new_object();
add_it_to_container_as(tex_name);
}
else
{
current_tex_pointer=what_we_found;
}
current_tex_name=tex_name;
}
}

void
glTexParameteri(GLuint tex_name,GLenum params)
{
//potential redundancy delegated
glBindTexture(tex_name);
//actually do something
current_tex_pointer->apply_stuff(params);
}

Now we’ve come round circle. The current GL model moves the burden to bind to the client application, and thus provides more opportunity for efficient code. That’s all.

The only reason that problem arises is because somebody had the bone-headed idea to make glGen* calls optional, and allow the application to just pick a 32-bit integer to and call glBind* on it. That means that the implementation has to internally keep around some collection of all the 32-bit integers that have ever been bound.

Once again, take a look at shader objects. Their equivalent glGen* calls are manditory, and do not necessarily return an integral value. They could return a pointer (potentially bad for 64-bit conversion), or some kind of 32-bit hash index that can be quickly used to lookup a value.

One problem with a state-based system is that it is a bit harder to track down bugs. If you have some code that sets some parameter on a texture, you can’t be certain which texture it is setting if a glBindTexture call isn’t sitting in front of it. As such, it is entirely possible that the given line of code is corrupting some other texture. This is not possible with an object-based approach (that being different from object-oriented, which deals with issues like inheritance and so forth, things that no low-level graphics API needs to deal with).

glTexParameteri(texObj, Params);
glTexParameterf(texObj, OtherParams);

is D3D way of doing things. Do you think it will be noticeable in terms of performance? I’m sure that you’ll be calling a whole set of functions, so another one in the bunch won’t be a big deal.

How would you solve the push/pop issue? If you forget one of them, finding the source is a problem. Perhaps giving each a unique ID.

Also, I guess it can happen that the driver won’t report the error???

I wish there was a “how to code the smart way for GL” document when I started.

Originally posted by Korval:
[b]The only reason that problem arises is because somebody had the bone-headed idea to make glGen* calls optional, and allow the application to just pick a 32-bit integer to and call glBind* on it. That means that the implementation has to internally keep around some collection of all the 32-bit integers that have ever been bound.

Once again, take a look at shader objects. Their equivalent glGen* calls are manditory, and do not necessarily return an integral value. They could return a pointer (potentially bad for 64-bit conversion), or some kind of 32-bit hash index that can be quickly used to lookup a value.[/b]
You need established names. Making object creation automatic is just icing on the cake, removing that capability doesn’t make it much easier. Instead of creating the object you’d throw an error.

But you still need to check whether you ‘know’ the object the client app wants to act on. “Integer or hash index” isn’t much of a distinction either. If you’ve never seen the hash … well, you get the idea.

One problem with a state-based system is that it is a bit harder to track down bugs. If you have some code that sets some parameter on a texture, you can’t be certain which texture it is setting if a glBindTexture call isn’t sitting in front of it. As such, it is entirely possible that the given line of code is corrupting some other texture. This is not possible with an object-based approach (that being different from object-oriented, which deals with issues like inheritance and so forth, things that no low-level graphics API needs to deal with).
If you really don’t know the current binding, you can always stick one in front of the function calls. So you can express “object based” in terms of “state based” but not vice versa.

class
ParanoidTexture
{
   private:
   GLuint gl_name;
   public:
   ParanoidTexture()
   {
     glGenTextures(1,&gl_name);
   }
   Parameteri(target, <...> )
   {
     glBindTexture(target,gl_name);
     glTexParameteri( <...> );
   }
};

ParanoidTexture texture;
texture.Parameteri( <...> );

There you go. You can wrap everything up and end up with the object based approach.

is D3D way of doing things.

You seem to say that as though the D3D way of doing things is categorically bad.

How would you solve the push/pop issue? If you forget one of them, finding the source is a problem.

Pushing and poping can be dealt with relatively easily in C++. If you encapsulate the push/pop calls in a C++ object (constructor pushes, destructor pops), you’ve got nothing to worry about. Not that I’m suggesting that the internal GL expose such an API, especially since it takes all of 2 minutes to write such a class.

Also, I guess it can happen that the driver won’t report the error???

Setting a texture parameter on the wrong object is not something that the driver can detect as an error. Setting the parameter on any object is legal; it is a symantic error, not an API error.

You need established names. Making object creation automatic is just icing on the cake, removing that capability doesn’t make it much easier. Instead of creating the object you’d throw an error.

No, if glGen* had control over the “names”, then it could generate names as it saw fit. The names in question could be actual pointers, or something that converts into a pointer after one quick memory access, or a relatively short lookup.

Because GL is forced to accept any object name regardless, the implementation must have some way to map any arbitrary object to a pointer to the internal object. Rather than having a simple function or even a cast operation, it becomes a complex search operation.

But you still need to check whether you ‘know’ the object the client app wants to act on.

Kind-of. I would actually prefer a debug and release version of the implementation. In debug, it can do glError and so forth checks to make sure that the texture object name really exists. However, in release, it should not even bother; just produce undefined behavior/crashes. Granted, that’s somewhat wishful thinking, but it would provide a negligable speed increase in situations where bindable object state is constantly in flux (which is, admittedly, not that frequent).

Think about Win32 programming (if you’ve ever done any). HWNDs are handles to a window. You have to call a function to create a valid one. If you call a Win32 function with an invalid HWND, it will fail (in debug, with an error of some kind). You don’t call a “bindHWnd” function; you just use the current one. It doesn’t impose much overhead in terms of searching because the contents of a HWND are controlled by the OS. It can put whatever info in a HWND that it takes for search/validation times to be low.

The real question is, if you had OpenGL to write all over again, from scratch (as a C-based API), with no consideration as to backwards compatibility, would you continue to use the current paradigm or would you switch to the one used by shader objects? I think, if the ARB had it to do over again, they’d go for the shader object (ie, object-based) version.

  1. First of all there is no overhead when using a well designed wrapper, there are ways to be fast and have some abstraction see blitz++
  2. Function overloading would cut down a lot of names now wouldn’t it?
  3. I see the pipeline as a stream so << it is, it might sound strange to those who don’t programm in C++ and stl but for those who do, I think it will make sense…
  4. A lot of state management could be handled in the client side, and you wouldn’t pay the overhead of glGet functions, not to mention easier debugging
  5. Be able to switch implementation directly
    you want lists? create a stream with lists
    you want arrays? create a buffered stream
  6. I do not expect programmers in C to like the idea, I expect programmers in C++ to like the idea.

I don’t think most low level C++ wrappers make sense with OpenGL 1.x.
And if it’s a higher level wrapper, then it’s not an OpenGL wrapper anymore.

However, I think that a low level C++ wrapper would be very useful with the proposed 3Dlabs interface for pure OpenGL 2.0; as there is a lot of abstraction that can be made to make life easier without any performance drop.

The class of code that I have found very useful to keep is for doing things that OpenGL doesn’t do for you, like linear algebra and object interaction. It would be really great if OpenGL included more support in this arena (via a major GLU update or another standard companion library). OpenGL does not compete well with D3D in this regard, and it is a barrier to entry for OpenGL developers.

Dito.
Plus GLU is totally obsolete in most area as a lot of functionalities are now handled more efficiently directly via OpenGL (e.g. mipmaps generation), or simply because other functions are too slow to be useful IRL as they use the immediate mode with a lot of overhead (e.g. Quadrics & Co).
Making a new lib would be a good thing. In C++ there are ways to make things very nicely while being faster, but of course there is the problem of C compatibility.

  1. Function overloading would cut down a lot of names now wouldn’t it?

Yes. You’re not the first one having the idea of using overloading with OpenGL, and you won’t be the last.
But it adds lots of confusion!
Types are very important in OpenGL. Depending on whatever you’re using: double or float, short or int, performance may vary a lot. Abstracting these details is NOT wise, you still want an absolute control over it; overloading make it difficult to do so.

The only point were overloading makes sense is when it’s used within templates; but again OpenGL is too low level to need most of these paradigms.

  1. I see the pipeline as a stream so << it is, it might sound strange to those who don’t programm in C++ and stl but for those who do, I think it will make sense…

It can make sense, sometimes.
I once used an output iterator pattern to send OpenGL commands, but it was working at a higher level than a simple wrapper around OpenGL. I still think that in that particular case it was one of the right things to do.

// send to standard output
std::copy(Graftal.begin(), Graftal.end(), std: stream_iterator<symbol_type>(std::cout, 0));

// send to OpenGL plotter
gl_graftal_plotter Plotter;
std::copy(Graftal.begin(), Graftal.end(), gl_graftal_output_iterator(Plotter));

But IMHO in most cases using streaming operators or output iterators is just a clumsy syntaxic change.

  1. A lot of state management could be handled in the client side, and you wouldn’t pay the overhead of glGet functions, not to mention easier debugging

You’re talking about a scenegraph. There is no way a simple C++ wrapper can take easily and elegantly take care of all these details.

EDIT: buggy code tags

[This message has been edited by GPSnoopy (edited 12-21-2003).]