|
Introduction
This one demonstrates usage of GL_ARB_vertex_program, GL_NV_vertex_program, and
GL_NV_vertex_program2.
If you don't have a NVidia card, then it's too bad but you can see that both
ASM based scripts are similar, but the NV version gives more power - specially the
newer GL_NV_vertex_program2.
We render optionally a sphere, cube, torus, cone, cylinder and a teapot (of course!) and
we light and texture them *without* doing anything special. We are just emulating
the fixed vertex pipeline here (loosly speeking).
You can turn the program on and off, compare the FPS in each case.
The Source
The ARB and NV API are quite close in this case.
The ARB version uses glGenProgramsARB (which I have renamed to glGenPrograms) and
the NV version has glGenProgramsNV. They use similar parameters. The
reason why I prefer getting rid of the ARB ending is that these
functions and tokens will likely become part of OpenGL's core in the next version. Here I will leave them as is.
//ARB
GLuint ARBVertexProgramID[10];
glGenProgramsARB(1, &ARBVertexProgramID[0]);
//NV
GLuint NVVertexProgramID[10];
glGenProgramsNV(1, &NVVertexProgramID[0]);
The ARB has glBindProgramARB (again, the ARB ending is removed in my source) and
NV uses glBindProgramNV and they both take similar parameters.
//ARB
glBindProgramARB(GL_VERTEX_PROGRAM_ARB, ARBVertexProgramID[0]);
//NV
glBindProgramNV(GL_VERTEX_PROGRAM_NV, NVVertexProgramID[0]);
The ARB has glProgramStringARB for uploading the vp to OpenGL and here is the
first difference. NV uses glLoadProgramNV.
With NV, binding is not necessary to upload a program, so you have to pass an ID
while in ARB, it is traditional to bind, then do whatever. For now, you must always pass
GL_PROGRAM_FORMAT_ASCII_ARB to the ARB version but it's possible unicode support will be
added in the future.
//ARB
char cBuffer[xxx];
int length;
glProgramString(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, length, cBuffer);
//NV
char cBuffer[xxx];
int length;
glLoadProgramNV(GL_VERTEX_PROGRAM_NV, NVVertexProgramID[0], length, cBuffer);
Now that you have uploaded, it's a good idea to check for errors.
With ARB, you can also check to see if native limits are respected and in my code,
I decided to do a fail if it is not respected.
In NV, you can't check if native limits are respected.
//ARB
GLint errorPos, isNative;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
glGetProgramiv(GL_VERTEX_PROGRAM_ARB, GL_PROGRAM_UNDER_NATIVE_LIMITS_ARB, &isNative);
//NV
GLint errorPos;
glGetIntegerv(GL_PROGRAM_ERROR_POSITION_NV, &errorPos);
That's the main part just to get things going. Another difference is
that NV allows you to query if a program is resident or not but in ARB,
they decided it's not very useful.
NVidia decided that ARB is not far off from it's own extensions (or the ARB decided NV is not far so they chose the same tokens) so some
functions have the same address and some tokens have the same ID.
If you learn one of the scripts and read the spec, you'll see that there is
plenty in common with the others.
GL_NV_vertex_program2 is quite interesting.
I only needed to write 1 script for handling the multiple lights, thanks
to flow control instructions (BRA which stands for branch) and subroutine
support (CAL for call and RET for return).
I think you lose some FPS though, but it's a neat feature nonetheless.
Conclusion
These extensions, unlike others, give incredible power to the programmer.
Use it wisely!
PS: It's not necessary to write multiple scripts. You can of course write one and
manipulate it in your program but I did not want to bother with this.
|
|
|