Longs Peak and beyond

The same reason why an underscore is neccessary in the first place prevents you from using overloading:
glTemplateAttribt_if(enum, int, float)
glTemplateAttribti_f(enum, int, float)
If that combination existed, it would be a great example of how NOT to design an API. Just try and explain the distinction there to people learning the API.

I don’t believe the ARB has to pick any one programming language.

However, just as we now layer “fixed functionality” on top of more flexible constructs, so the C API of an true object-based API should not be the limiting factor anymore. But I’m not really arguing to ditch C support, just to improve C++ support. And yes, I’d love for an official header file for any language people care about. If the ARB simply wants to hold a contest for the best free version of each, which they then “bless” as official, that’s fine by me. But I think there’s an opportunity for more improvements in the driver’s seat, as well as under the hood.

P.S. I don’t know why people are arguing the definition of polymorphism. Don’t take my word for it. Look it up. It’s not just virtual functions. :slight_smile:

Great. Why would you rather want to have something that works in most cases, than something that works in all cases, in any language from now until forever. Something that is clear and precise, needs no workarounds and can easily be put into a wrapper, if one thinks that C++ is the one and only language and everything needs to be in C++ ?

I work with C++ everyday and i like the language very much. But things that make no sense, make no sense, period. Someone who knows his craft knows what tools to use for what. You don’t use a power shovel to put a nail into a wall, do you?

Jan.

Ok, the example with int and float is not very well chosen. Let’s try something more concrete:

glTemplateAttribt_2i(enum, int, int) … set an attribute with type 2i
glTemplateAttribti_i(enum, int, int) … set an int-indexed attribute with type int

Again I don’t know if this combination exists, but I think it is not so absurd to assume the existance of both ivec2-typed attributes and array-of-int-typed attributes.

I think the difference is clear enough. If you think this is bad API design, then I would love to see your suggestion how this could be made any more clear.

There are lots of “features” in C++ that I try to avoid in my APIs until I know I need them. Even virtual functions can often be overkill. However, one thing C++ can do very well is make APIs (especially those featuring objects…) very simple to understand and quick to control.

Overmind, your example still highlights the problem with the overly terse C APIs.

In this case, the first approach I’d try in C++ is see if the (enum,int,int) bits can be wrapped in their own typed object for clarity. In the case of glTemplates, if these are client-side objects, it might be okay to actually build a GLTemplate class with actual getters and setters specialized to the attribute and its various parameters. But trying to avoid any appearance of big [Microsoft-like] versioned gettr/settr structs, I’d start with a lot of little ones, where more can be added down the road without changing any names or offsets. Assuming some GL.h header base class like:

template <int GLID, typename T1, typename T2>
class glAttrib
{
protected:
    inline glAttrib();
public:
    inline void Set(const T1& t1, const T2& t2);
    inline void Get(      T1& t1, T2&       t2) const;

    inline void Apply(glTemplate*) const;
    // type-specialized implementations of Apply can call the proper glTemplateAttibXX_X function under the hood
...
private:
// storage 
// T x; 
// T y;
// a variable number of params could be handled in 
// several ways, one of which is to push these 
// into the more derived classes.
};

// here go the Enum replacements:

struct glSomeAttrib  : public glAttrib<GL_SOME_TOKEN, int, int>  {   glSomeAttrib(int x, int y) { Set(x,y); } };
struct glOtherAttrib : public glAttrib<GL_OTHER_TOKEN, int, int> {   glOtherAttrib(int x, int y) { Set(x,y); } };

// And perhaps a few more wrappers for convenience:

template <typename A>
void glTemplateAttrib(glTemplate *ptr, const A& attrib) { A.Apply(ptr); }

class glTemplate
{
   GL_TEMPLATE_HANDLE handle;
// omitting lots...
public:
  template <typename A> inline void SetAttrib(const A& attrib) { A.Apply(this); }

};

The main goal is to have the compiler find mismatches between enums and function parameters and avoid more runtime errors while adding more clarity. But it might also be nice for us to be able to use these classes to store attributes or whatever object-ish stuff we’re talking about in our programs, for faster/cleaner dispatch – not the whole driver-side objects themselves, which we shouldn’t ever know or rely on, but the attribute tuples themselves should be safe.

So, in this case, I’d probably subclass this GLAttrib base for each specific enum type, specializing the parameter type(s) to fit each precisely and trying to add semantic information in the names, or in additional fields as needed.

In the case of an int-indexed attribute vs. a pair of ints as an attrib, those would be two different attribute types (classes) and therefore the names would be clear and different.

Anyway, all that header “goodness” aside, the end user would see and use a much simpler API:

template->SetAttrib(glSomeAttrib(x,y));

including the option of keeping these objects around:

glSomeAttrib A(x,y);
template->SetAttrib(A);

or slightly more C-like:

glTemplateAttrib(template,glSomeAttrib(x,y));

“GLSomeAttrib” might be better to connote data structures vs. function calls than lower case. Namespaces are even better. The glSomeAttrib could potentially carry the suffixes for extra clarity, or even be templatized itself for more options. [The downside in that case is the compiler error when trying to use an unsupported template combination is more cryptic than it should really be. See BOOST_STATIC_ASSERT for some ideas on how to provide better custom compile-time errors.]

All of this can easily wrap the messier (IMO) C API without needing a different DLL. Show me any case it can’t handle and I’ll make a quick adjustment. :slight_smile:

And also, btw, this is the leasst intrusive of many approaches. If we took a “mixin” approach, we could even do away with setting up templates in piece-meal fashion. A custom client-side class could be composed of the elements you wanted. This class could be a runtime object you could use. But it could have enough meta information to describe itself to the driver, as GL-templates seem to do. But that’s more of an under-the-hood change, so I’m not actively suggesting that, though I use it myself for some really flexible vertex buffer wrapper classes.

If you think this is bad API design, then I would love to see your suggestion how this could be made any more clear.
Simple: you can only set one value at a time. The Longs Peak example already shows us this: you set the width and height in separate calls.

If you are setting something that is intrinsically a vector, then you use “fv” or “iv”, not “iii” or “3i” semantics.

yep i agree with korval, keep it as simple as possible ( so perhaps u type more, but hey u have copy + paste, RSI sufferers aside a little typing never harmed noone – )
anyways personally i think the current API naming method is ideal, ok so maybe not OOP but so!
to quote the cliche, if it aint broke dont fix, its the one thing ive always admired about gl is its syntax

a little typing never harmed noone

if it aint broke dont fix
Fully agreed on both points.

About the whole thing being confusing for beginners: That’s what the new glu functions will be for. I don’t expect people totally new to GL will be able to understand how to use Long Peaks without any utility function right away.

And again about separate program bindings for different pipiline stages.
There is currently linkage stage in OpenGL with working with GPU programs. And that is very well, because I’m just specify
varyings with same names and linker doing all job - binding all resources between differen programmable units, in opposite
with Cg/HLSL or ASM ARB/D3D Shaders where interaction between programs done through semantics ( TEXCOORD0, COLOR etc.)
( Semantics does not mean at all in D3D10, - output layout from one stage must coincide with input layout on next pipeline stage -
for example vertex shader must always write Vertex_Position register , but in Fragment shader I do not use that register,
but it still must be declared here - it very inconveniently, especially when shader’s code auto-generated,
and all shaders combinations known only in run time, don’t say about stupid errors at all ).

Now in LP we can hold programs for different stages separately. Is there linkage stage ? -
It is done during binding time ? - how runtime can determine “program binding completeness” for that?

"for example vertex shader must always write Vertex_Position register , but in Fragment shader I do not use that register, "

The vertices are used by the triangle setup stage and then by the rasterizer.

Not to belabor the naming issue, but what about this:

glTemplateAttribInt
glTemplateAttribFloat

(in the off chance it wasn’t already considered and summarily rejected)

It’s a clean break from the other tradition, but I think it may avoid confusion and, perhaps more importantly, the underscore.

Cheers

It’s a clean break from the other tradition, but I think it may avoid confusion and, perhaps more importantly, the underscore.
Two reasons.

One, it’s rather wordy.

Most importantly, two, it doesn’t convey the proper information. The reason that the <name type> is there is because attributes need it. Setting a value in a struct works like this:

structVar.structMem = value;

Each of these is represented in the glTemplateAttrib call. We know that the first parameter is “structVar”; the template object we’re setting the value on. The “structMem” is a name that, in the case of glTemplateAttrib, has one of several possible name types. The name could be a regular token, a token plus an integer, or maybe something else too.

And “value” is a value, which has a type.

So there’s 3 types to work with, one of which is known (the type of the object, which is always template attribute). The function names must be differentiated on both name type and value type.

I rather think that token is implicit in the TemplateAttrib portion of the name (what are we referring to with TemplateAttrib, if not a predefined token).

To handle both cases, (token, value) or (token, index, value), maybe something like this:

glTemplateAttribInt(template, name, value)
glTemplateAttribIndexInt(template, name, index, value);

or

glTemplateAttribElementInt(template, name, index, value);
glTemplateAttribArrayInt(template, name, index, value);

Respectively, I think these are roughly equivalent to

template.name = value;
template.name[index] = value;

unless I’ve misunderstood the proposed purpose of the (token, index) tuple.

Cheers

Edit: added another index alternative…

glTemplateAttribIndexInt
Does the index apply to the integer value or to the template attribute?

That’s why the underscore is there. It provides explicit demarcation between the template attribute type and the value type.

quote: a little typing never harmed noone

quote: if it aint broke dont fix

quote: That’s what the new glu functions will be for. I don’t expect people totally new to GL will be able to understand how to use Long Peaks without any utility function right away.

Wow. I’m really surprised. The people responding here are usually very giving of their time to help newcomers learn OpenGL. But here you seem quite reluctant to help steer an API being redesigned to be easier and simpler be that for both new users as well as well as veteran users such as yourselves.

The idea that you don’t mind a little extra typing or potential confusion is fine. But a key problem with the evolution of OpenGL thus far is that the best new features have been the ones that are also hardest to learn and code – often because the API does not give compile-time feedback when we do something wrong. It compiles, runs, and all we get is a blank window and [if we’re lucky] a GL error message.

The key thing I’m pushing for is not to make it easier for pros (which is a fine thing in and of itself). I’m pushing to help eliminate beginner mistakes, which I’d think you’d be in favor of too, given how often you all have to respond to such posts on these boards. Or maybe you like that part too much to give it up? :wink:

And as a reminder, I’m only talking about a C++ (or other OOP language) overlay on the C API. Saying “that’s what the GLU functions are for” is a strange way to disagree with that request. It doesn’t much matter if the header file says GL.H (with a C++ ifdef) or GLU.H as long as the result is a lower learning curve and more API hand-holding for those that need it.

And let’s not forget, the main reason OGL is so easy to learn are some of the very features that are being depreciated (or at least layered) – glVertex3f, etc… Not that depreciation is wrong. But we should balance that with at least comparable simplicity for newbies.

Anyway, I think this is falling on deaf ears. I’ll personally be fine no matter what the API turns out to be.

Back to work for me. :slight_smile:

steer an API being redesigned to be easier and simpler be that for both new users as well as well as veteran users such as yourselves.
These are mutually exclusive design goals. Particularly because that which makes the language useful for veterans doing real work is exactly that which makes it difficult for beginners.

Real developers need an API that is fast-path, guaranteed. Beginners just need to get something on the screen. Advanced users don’t have a problem with needing to use 20 function calls to build the template objects necessary to create, for example, an image, as long as that image is guaranteed to be on the fast path. For a beginner, this is onerous; they just want a textured polygon.

As OpenGL 2.1 proves, you can’t do both effectively. You have to pick one. Furthermore, it’s better to pick the advanced users over the beginners because, worst comes to worst, you can aways wrap things in a more intuitive API. You can’t “unwrap” that intuitive but slow API in an unintuitive but fast one.

And as a reminder, I’m only talking about a C++ (or other OOP language) overlay on the C API.
And I still don’t see the point of making the ARB spend valuable time doing it. Not when there are other developers who are perfectly willing to create such a thing.

The job of OpenGL is to abstract the hardware functionality as closely as possible. The main aim of the redesign of OpenGL is to boil it down to the bare minimum interfaces which allow for every conceivable future extension without the need for new fundamental interfaces to be added.
If communication with the hardware is done using a command stream, which it is, then the API should be command stream orientated, despite the fact the resources are conceptually objects.
Leave the C++ wrappers to 3rd parties - just as people have wrapped win32 functions in C++ wrappers such as MFC or wxWidgets.
The best one will become the new GLUT.
The reason I personally am against any further discussion about this is because from my experience the ARB take an eternity to actually get things done, and so feature creep is something we, as serious OpenGL users, do not want to encourage.

I want to see this Longs Peak API released within the next few months - I can see no reason why it should take any longer than that. Hardware is simple now, user-defined shaders have taken the complexity away from the driver.

+1

Yeah, i second that.

Originally posted by Korval:
Does the index apply to the integer value or to the template attribute?

I think it applies to the template attribute.

One possible source of perceived ambiguity is that traditionally the type suffix has indicated the parameter type, but not necessarily the target type, as is the case with say glVertex2i. That’s why I thought that spelling out the typename would serve to hedge against that perfectly understandable preconception; here the parameter type must match the target type (this makes little sense to me, otherwise). In sum, the typename suffix is always the target value’s type, while I imagine the index type would always be an uint (although other arrangements could be made).

I too should add that I’ll be perfectly content with whatever the ARB decides upon, however deeply unsatisfying I personally find the underscore to be :wink:
(The thing about underscores is, once they get a foothold, you’ll never be rid of them!)

Cheers

Originally posted by Flavious:[b]
glTemplateAttribInt(template, name, value)
glTemplateAttribIndexInt(template, name, index, value);

or

glTemplateAttribElementInt(template, name, index, value);
glTemplateAttribArrayInt(template, name, index, value);[/b]
or:

glTemplateAttribi(template, enum, int) // replacing glTemplateAttribt_i
glTemplateIndexedAttribi(template, enum, int, int) // replacing glTemplateAttribti_i

This would retain the oldschool suffixes and their meaning, if anyone happened to care…

Originally posted by Korval:
[b] [quote]glTemplateAttribIndexInt
Does the index apply to the integer value or to the template attribute?

That’s why the underscore is there. It provides explicit demarcation between the template attribute type and the value type. [/b][/QUOTE]So far we’ve seen 2 ways of specifying an attribute name: token and {token, index} tuple.
As it has been mentioned above, they correspond to ‘struct’ and ‘array’ member access in C.

Notice that both of these ways are used in the current OGL. The {token, index} can bee seen in indexed tokens names, like: GL_LIGHTi, GL_TEXTUREi, GL_COLOR_ATTACHMENTi_EXT, GL_DRAW_BUFFERi_ARB, and others. So, it’s nothing new here, except the new solution avoids problems of allocation of token number ranges.

Now, the “underscore” notation leaves place for possiblities other than these two. But honestly, will we ever need any?