Archived

This topic is now archived and is closed to further replies.

wrapping up those dirty dirty functions

This topic is 5127 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

im currently building a open gl wrapper, to make life easier. I have a few simple questions. There are several versions of the glColorx function. Each one allows you to specify colors by different types (and eventually maps each one, regardless, to a value between 0 and 1, being of float type). Anyways, ive taken the oppurtunity that lay before me, to clean this up with function overloading, and default parameters (there''s only one color function now, but several versions of it, the compiler will automatically know which one, depending on the data its given) I have my doubts on trusting the compiler. Here is an example... gl.Color(1.0f,1.0f,1.0f); Now, if the compiler interprets those numbers, each as floats, it would call the correct color function within the class, which would then call... glColor4f(1.0f,1.0f,1.0f,1.0f);//1.0f is default parameter in my class, for alpha now what if we do this gl.Color(1,300,70); which one is the compiler going to choose? Is it actually smart enough to know that im not using an unsigned char (or ubyte)? Im not sure, could someone sum this up for me? (i think you get the idea of what im doing) Also, what is an easy way of expressing the following: highest value for type double highest value for type int (i know its system dependent, but that doesnt help...) highest value for type unsigned int (again, system dependent?) so far, i''ve defined each function within my class:
	void Color(GLbyte red,GLbyte green,GLbyte blue,GLbyte alpha=127);
	void Color(GLdouble red,GLdouble green,GLdouble blue,GLdouble alpha=0);//find out range (highest value?)

	void Color(GLfloat red,GLfloat green,GLfloat blue,GLfloat alpha=1.0f);
	void Color(GLint red,GLint green,GLint blue,GLint alpha=0);//find out range (system dependent)

	void Color(GLshort red,GLshort green,GLshort blue,GLshort alpha=32767);
	void Color(GLubyte red,GLubyte green,GLubyte blue,GLubyte alpha=255);
	void Color(GLuint red,GLuint green,GLuint blue,GLuint alpha=0);//find out range (system dependent)

	void Color(GLushort red,GLushort green,GLushort blue,GLushort alpha=65535);
but im not sure if the compiler is going to know which one to automatically choose when the user compiles his application using this wrapper

Share this post


Link to post
Share on other sites
gl.Color(1,300,70);

300 is a short. The compiler will look for a function that can accomodate it.

highest value for type double

#include<limits>
std::numeric_limits<double>::max()


highest value for type int

std::numeric_limits<int>::max()

highest value for type unsigned int

std::numeric_limits<unsigned int>::max()

but im not sure if the compiler is going to know which one to automatically choose when the user compiles his application using this wrapper

If it doesn't, it will tell you that the function call is ambiguous.



[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]


[edited by - Fruny on November 30, 2003 1:08:22 AM]

Share this post


Link to post
Share on other sites
If you type it yourself, append a specifier:

3.0f is treated as a float
if you append u, it becomes an unsigned type, not sure which though
Or you could use casting, eg static_cast300 would make it be treated as an unsigned byte

Share this post


Link to post
Share on other sites
just to bring up a minor point, but with this ''wrapper'' are you doing any more than calling one function from within each function?
If your not then, tbh, i dont see the point, as all you''ll be doing is adding an extra function call each time you want to call something OpenGL related, kinda pointless i feel...

Share this post


Link to post
Share on other sites
quote:
Original post by _the_phantom_
just to bring up a minor point, but with this ''wrapper'' are you doing any more than calling one function from within each function?
If your not then, tbh, i dont see the point, as all you''ll be doing is adding an extra function call each time you want to call something OpenGL related, kinda pointless i feel...



But that''s not the point. A good optimising compiler would inline the functions anyway. The idea is to unify the different glColor* functions into a single interface, letting the language semantics decide which function should be called.

One question I have with this is why are you using all the different representations of a color? One or two suffices for me. In the long run you are better choosing one representation and sticking to that throughout the code. Using different representations will only confuse you later on - e.g. was that value of 100 for red supposed to be a uint, uchar or short? It would have different meanings in each of these cases.

James

Share this post


Link to post
Share on other sites
I suppose the advantage of some formats might be bandwidth usage (assuming they aren''t all just converted to floats by the driver). 128 bits of data for glColor4f[v] or 32 bits for glColor4ub[v].

Share this post


Link to post
Share on other sites
quote:
Original post by jamessharpe
But that''s not the point. A good optimising compiler would inline the functions anyway. The idea is to unify the different glColor* functions into a single interface, letting the language semantics decide which function should be called.



ok, given that then, why use a class?
a namespace would do the same job, heck just putting the functions somewhere global would do the same job.

for example, OGL::Color(1.0f,1.0f,1.0f) would do the same job and removes the redundancy of having to have an OpenGL object laying around.

Share this post


Link to post
Share on other sites
it does much more than that...

it completely removes the possibility of redundant state changes, it unifies rundundant functions (glcolor, glvertex), it watches your ass (prevents you from sending null pointers where applicable, or negative values, and others). It doesnt operate at a per-vertex level, because that would be extreme speed loss (as someone mentioned earlier). When you call something like gl.Enable(SOME_CAPABILITY), it will only enable it if its not already enabled.

Things like this help to make opengl work better. Its like a shadow state layer over the opengl layer. Since its such at a low level, you're able to take advantage of this.

For instance, (another good example)

gl.BlendFunc(something,something)

if the current blend func is already something,something, there is no need to call it again, cuz we're already in this blending mode.

gl.BindTexture()

prevent binding of a texture that is already bound

things like this are not watched by your opengl drivers, you have to make sure it doesnt happen on your own.

check out this thread->
http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/001787.html


the wrapper even goes one step further, and makes extensions seem like their already part of open gl

gl.MultiTexCoord2f()


AND! if the extension isnt supported, the wrapper emulates the effect

i guess you could call this wrapper direct x, lmao...

[edited by - fireking on November 30, 2003 8:14:01 PM]

Share this post


Link to post
Share on other sites
taking ur point on trapping redundancies, have u considered the additional execution layers involved in wrapping the function into class functions? co assuming u''re wrapping at an extremely low level, such as Vertex(...) to substitute glVertex*, then wouldnt these be true:

1. class functions have an explicit passing of the ''this'' pointer making function initiation ever so slightly slower.
2. i dunno if object overloading works anywhere like virtual functions, but i suppose mapping the proper overloaded function could entail a speed hit.
3. though these hits are small, but at low levels, they may end up being called enuf times to accumulate their bloat

also, thinking about state changes verification, it is a nice thing to avoid state changes when its not already necessary. But that would perform some logic computation which would usually be quick. but are state changes really THAT taxing to make this necessary versus verifying?

just curious

Share this post


Link to post
Share on other sites
quote:
Original post by fireking
When you call something like gl.Enable(SOME_CAPABILITY), it will only enable it if its not already enabled.



I would trust the OpenGL libraries already do that kind of things.




[ Start Here ! | How To Ask Smart Questions | Recommended C++ Books | C++ FAQ Lite | Function Ptrs | CppTips Archive ]
[ Header Files | File Format Docs | LNK2001 | C++ STL Doc | STLPort | Free C++ IDE | Boost C++ Lib | MSVC6 Lib Fixes ]

Share this post


Link to post
Share on other sites
quote:
Original post by Fruny
I would trust the OpenGL libraries already do that kind of things.

Surprisingly enough, it may not. From the OpenGL.org site (sorry, didn''t catch the HREF):
quote:

The advice in this section is focused on the matrix mode state, but pitfalls that relate to state changing and restoring are common in OpenGL. OpenGL''s explicit state model is extremely well suited to the stateful nature of graphics hardware, but can be an unwelcome burden for programmers not used to managing graphics state. With a little experience though, managing OpenGL state becomes second nature and helps ensure good hardware utilization.



The chief advantage of OpenGL''s stateful approach is that well-written OpenGL rendering code can minimize state changes so that OpenGL can maximize rendering performance. A graphics- interface that tries to hide the inherently stateful nature of well-designed graphics hardware ends up either forcing redundant state changes or adds extra overhead by trying to eliminate such redundant state changes. Both approaches give up performance for convenience. A smarter approach is relying on the application or a high-level graphics library to manage graphics state. Such a high-level approach is typically more efficient in its utilization of fast graphics hardware when compared to attempts to manage graphics state in a low-level library without high-level knowledge of how the operations are being used.



If you want more convenient state management, consider using a high-level graphics library such as Open Inventor or IRIS Performer that provide both a convenient programming model and efficient high-level management of OpenGL state changes.




"Sneftel is correct, if rather vulgar." --Flarelocke

Share this post


Link to post
Share on other sites
quote:
Original post by CraZeE
taking ur point on trapping redundancies, have u considered the additional execution layers involved in wrapping the function into class functions? co assuming u''re wrapping at an extremely low level, such as Vertex(...) to substitute glVertex*, then wouldnt these be true:

1. class functions have an explicit passing of the ''this'' pointer making function initiation ever so slightly slower.



didnt consider that, although i dont think it will be that much of a burden? Any way to specify that you dont want the this pointer? (er actually, its needed in a few places, for checking states)

quote:

2. i dunno if object overloading works anywhere like virtual functions, but i suppose mapping the proper overloaded function could entail a speed hit.



not sure what you mean here...

quote:

3. though these hits are small, but at low levels, they may end up being called enuf times to accumulate their bloat



highly unlikely. The entire point of the class is to prevent unneccessary function calls. I figure thats what a lot of engines do anyways.

quote:

also, thinking about state changes verification, it is a nice thing to avoid state changes when its not already necessary. But that would perform some logic computation which would usually be quick. but are state changes really THAT taxing to make this necessary versus verifying?

just curious


it is definately necessary to keep track of the state changes on your own. If you design your entire engine so that it never binds the same texture twice, then kudos to you because you just did what everyone is trying accomplish. This is one way of doing it (kind of). Im not that great at programming, most smart people will be able to admit that (because programming is so vast). If i was carmack, i wouldnt be asking/talking about stuffs like this here, because I''d already know . But since I dont, i come here to express my ideas. If you can find good reasons why my ideas aren''t good ideas, I appreciate you telling me. All of you .

I''m beginning to think that writing a shadow function for every single gl function there is, tis a big rediculous, so im currently re-evaluating how I should accomplish this elegantly. But the ideas ive already expressed are definately good ones. The state watching, and the function overloading is ok. Im just not so sure if i should wrap EVERY function. I need to take a look at all the functions, as a whole, and figure out which ones would be the best ones to wrap. The ones that should not be wrapped should just be inlined (copy the original gl function), because you still want to have everything localized. (you dont want to call gl.Vertex at one place, then call glBlendFunc somewhere else).

Share this post


Link to post
Share on other sites
oh and to clear something up

the state query is fast, all states are stored in a boolean array. The array is synced once (at start up). Then, from there on, when you enable or disable something, we dont ask opengl if its enabled, we refer to our array. The array is completely accurate this way (you dont have to ask opengl, because you keep track of it accurately). Since its synced once, all states are accurate from the get go. The class keeps track of it from then on. Wanna know if something is enabled, just call GetState(state), which returns states[state]''s value (true or false).

Share this post


Link to post
Share on other sites