Jan
09
2010
0

Overloaded Virtual Methods

This week I came by a new kind of bug that I’ve never had before, and is up the top of bugs I’ve came by when using CodeWarrior, the top still being invisible syntax.

Though I don’t think anything can top that, it can be hell if you have garbage at the end of a line, and you can’t see it when even though the compiler tells you something is wrong, luckily to solve that one, you just press a key or change someone on the same line and it makes it visible.

Anyways, this bug is caused by having overloaded pure virtual or virtual methods in a base class, but only implementing some of the them in the derived class.

It causes the compiler to not acknowledge any of the other overloaded functions, which you can end up spending a lot of time trying to solve if you’re not familiar with it.

The below code shows an example base class for causing this error.

class BaseClass
{
    //
    // Functions
    public:
        //
        //
        BaseClass()
        {
        }

        //
        //
        virtual ~BaseClass()
        {
        }

        //
        //
        virtual int Multiply( const int inValue1 )
        {
            return 2 * inValue;
        }

        //
        //
        virtual int Multiply( const int inValue1, const int inValue2 )
        {
            return 2 * inValue1 * inValue2;
        }
};

If in the derived class you implement one of these, as shown below, and then try to access one of the other overloaded that are only implemented in the base, the error will happen, telling you something like there are no overloaded versions of that function that take that parameters you are giving.

class DerivedClass : public BaseClass
{
    //
    // Functions
    public:
        DerivedClass()
            :
            BaseClass()
        {
        }

        //
        //
        int Multiply( const int inValue1 )
        {
            return 3 * inValue1;
        }
};

//
//
int Main()
{
    DerivedClass testClass;
    return testClass.Multiply( 2, 3 );
}

Now I’m sure I had use overloaded virtual functions before, so why was this happening now. So after a bit of searching I found out that only some compilers have support for this.

The reason the error occurs, is because the compiler generates a list of virtual function names to link to in the class. However, if it fails to find a function matching the name of what is being called, it will check the base.

Because we had overloaded only one of overloaded virtual functions, it ended its search in the derived class. And when it tries to associate the correct function call with the correct function, it notices that the function has a different number of parameters to that which is recorded in the list, and causes an error.

Now there is a way around it, you explicitly tell the compiler to use the functions listed in the base by use of the “using” keyword.

class DerivedClass : public BaseClass
{
    //
    // Functions
    public:
        //
        //
        DerivedClass()
            :
            BaseClass()
        {
        }

        //
        //
        using BaseClass::Multiply;

        //
        //
        int Multiply( const int inValue1 )
        {
            return 3 * inValue1;
        }
};

//
//
int Main()
{
    DerivedClass testClass;
    return testClass.Multiply( 2, 3 );
}

This will not error, since when the compiler is generating a list of functions, it will also include the Multiply functions in the base. The using keyword also has scope, so putting it in public will make the functions accessible outside the class.

Written by Kaluriel in: Code | Tags:
Oct
06
2009
0

Mutable and Volatile Keywords

I’ve seen mutable used only a few times, and not thought much about it until recently went I was reading about what it does on MSDN. This keyword makes a variable ignore whether a function is const or not within a class.

Below is an example of one way it could be used.

class MyClass
{
 //
 // Functions
 public:
  //
  //
  MyClass()
   :
   m_value( 10 ),
   m_valueGetCount( 0 )
  {
  }

  //
  //
  int GetValue() const
  {
   // Class variable can be changed despite function being declared const
   ++m_valueGetCount;
   return m_value;
  }

  //
  //
  unsigned int ValueGetCount() const
  {
    return m_valueGetCount;
  }

 //
 // Attributes
 private:
  int m_value;
  mutable unsigned int m_valueGetCount;
};

My experiences with it have been for thread synchronization objects I use such as my Semaphore class. For some reason the MacOSX implementation of the semaphore doesn’t allow me to get the count, so I had to add a variable myself.

The mutable keyword allowed me to keep the class usable within a const scope, which the use of const_cast().

Another keyword I seem to use with threads a lot is volatile. It prevents variable value being cached, forcing it be read from memory every single time it is access.

//
//
namespace
{
 volatile bool l_myBoolean = true;
}

//
//
void main()
{
 //
 createSomeOtherThread();

 //
 while( l_myBoolean )
 {
  // do nothing
 }
}

//
//
int someOtherThread( void * inParam )
{
 l_myBoolean = false;
 return 0;
}

In the case of a while loop that relies on a boolean that gets updated in another thread, this has the potentially that the compiler will cache it and thus the loop will never end.

Written by Kaluriel in: Code | Tags: ,
Sep
19
2009
0

Athena: Word Wrap

Athena: Word WrapOne thing I hate doing is writing classes that will output text, as well as handle special character sequences that get replaced by images. And while all this is happening, having it word wrap as well.

So I wrote a quick word wrap template class today that will do this. It doesn’t give line spacing yet, which I’m still unsure whether or not it should be this.

The way it works is when you create the word wrap object, you can pass to it’s constructor a value for the maximum width a line can be, this can be a floating point value, or an integer (it defaults to integer).

Then you call Parse() and give it a string, it will go through that string, checking the width of characters until the accumulated character widths are greater than the maximum width, or a new line is found. It will output this line of characters and move onto the next bit.

If it finds a word that is longer than maximum width, it will do one of two things. First if it is at the start of a newline, it will cut the word at the point it goes over. If it is already part way into a line, it will cause a new line and put the word on the next line.

I’ve included with this blog entry the header for the word wrap class, it comes as part of a test project in Xcode (it uses the Lorem Ipsum text), but the source and headers should work in another C++ IDE.

Download Source: Athena Word Wrap Source (Version 1.0.0)
Written by Kaluriel in: Athena, Code | Tags: , ,
Sep
10
2009
0

Athena: Bezier Curves

Bezier CurveWhen animations are exported from Maya through COLLADA files, they come out in a variety of formats depending on how the animation was implemented, and what is being animated.

One format is the bezier curve, a curve made from four points. Two fo the points are the start and end position, and the other two are control points that describe how it should curve.

Bezier Curve ApplicationSince all three axis can be animated, I made it possible to make a 3-component vector bezier class using the bezier class I created, and just calculate the point coefficients once, passing them to the bezier class to get the position. This of course only works if the time length for curves are the same on all three axis.

I’ve made a sample, it is an Xcode project that uses GLUT to render a 2D bezier and a 3D bezier. The code should work with other IDEs. One thing I should warn is that this bezier class only works when the time step is constant between the control point and it’s respective point.

P0 (0, 0) … keypoint 0
P1 (2, 10) … keypoint 1
C0 (0.666667, 42.6212) … control point 0
C1 (1.33333, 10) … control point 1

T0 = (C0 – P0) -> (2, 42.6212)
T1 = (P1 – C1) -> (2, 0)

The above sample is from the COLLADA forum, as you can see the time step is 2 for both T0 and T1. The same post describes how to calculate the S0 if your time step is not constant.

Download Source: Athena Bezier Source (Version 1.0.0)
Written by Kaluriel in: Athena, Code | Tags: , ,
Aug
23
2009
0

Escape From ASDA (Source)

The quests can now be authored more in Lua. There are conditionals for whether the quest is active, and whether the quest is complete.

I’m tempted to make the entire game in Lua, and just use the application as an intermediate for calling functions and rendering. Then I could just execute functions within rooms / npcs for the relevant dictionary word.

There are still some flaws in the text output, like it doesn’t split up words onto new lines if they are longer than the line width.

Next on the list is 8×8 Board Games, get rid of that horrible green.

Download Source: Escape From ASDA v2.1.0 (MacOSX)
Download Source: Escape From ASDA v2.1.0 (Win32)
Written by Kaluriel in: Escape From Asda | Tags:
Aug
16
2009
0

Escape From ASDA (Update)

Escape From ASDA - Title ScreenThis weekend I’ve been going through files I’ve been meaning to upload to my website for some time now.

I’ve got all the World of Warcraft addons finished, so I began on the C++ games I made at university.

Escape from ASDA is one of them, I was gonna upload it as it was but after noticing a few memory leaks.

As I started to clean up the code, and then got a little carried away and practically rewrote most of it.

Escape From ASDA - IngameOriginally it used a custom text file format for data, that was % deliminated, now it uses Lua which makes it at lot easier to understand when editting.

I also modified the title screen to use a bit of ASCII art, and made the commands more flexible.

Unfortunately unlike v1.0.0, it does not support mouse input for navigation. And since you can’t seem to change the console caret in MacOSX, I’ve had to make a custom console buffer that I use to render to before outputting.

There are a few more changes I plan to do to make the game script more flexible before I upload the source, but for now where is the binaries for Win32 and MacOSX.

Making it compile on WIN32 again was a pain, much more than it should have been, maybe its just the Microsoft implementation of STL…

Download Binary: Escape From ASDA v2.0.0 (MacOSX)
Download Binary: Escape From ASDA v2.0.0 (Win32)
Written by Kaluriel in: Escape From Asda | Tags:
Jun
01
2009
0

Athena: Cheap(er) Per-Pixel Directional Lighting (cont)

In my previous blog entry, Athena: Cheap(er) Per-Pixel Directional Lighting, I wrote how I had an idea for post process lighting calculations. Well, like many other things, it has already been done before, in fact a long time ago, 1988. It is known as Deferred Shading.

The wiki article also mentions something else that I didn’t take into considering, and that is transparent objects, since there would be more than one lighting equation needed.

On the whole though, I’m glad I got a chance to implement it, one more thing I know how to do.

Written by Kaluriel in: Athena, Code, Shaders, Tutorials | Tags: , ,
May
31
2009
0

Athena: Cheap(er) Per-Pixel Directional Lighting

Per-Pixel Directional Lighting through Post ProcessAs mentioned in Athena: More Uses for Framebuffer Objects, I have thought up a way of doing lighting using colour buffers, at the moment it is only directional lighting however.

But the great thing is, depending on how many objects are in your scene, and how much overdraw can happen, this method is faster (I think, I don’t know the cost of writing to a second colour attachment).

Colour Shader

The colour shader is just a basic shader I’ve setup to show. First of all the vertex shader…

//
// Varying Variables
varying vec3 Normal;

//
// Vertex Shader entry point
void main()
{
Normal = normalize( gl_NormalMatrix * gl_Normal );
gl_Position = ftransform();
}

As you can see this is just a basic vertex shader, transforming a vertex position into screen space and passing the normal onto the fragment shader through a varying variable type.

Now the fragment shader…

//
// Varying Variables
varying vec3 Normal;

//
// Fragment Shader entry point
void main()
{
vec3 N = normalize( Normal );
float kDrawLit = 1.0;
gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0 );
gl_FragData[1] = vec4( N, kDrawLit );
}

This is a typical fragment shader as well, using draw buffer zero for the unlit texel colour. However, I’ve normalised the interpolated normal that was calculated for this texel and I’m outputting it to draw buffer one, along with another value ‘kDrawLit‘.

When the w component of draw buffer 1 for this texel is set to 0.0, the texel will not have any lighting calculations performed on it in the post process. I came up with this when I started thinking about rendering a HUD before the post processing.

I’ve chose just to output red as a colour, anything is fine, such as a texture that is mapped to the object in question.

Per-Pixel Lighting Shader

Again, another simple vertex shader, passing a transformed vertex and texture coordinate to the fragment shader…

//
// Varying Variables
varying vec3 v_lightDir;
varying vec3 v_halfVec;

//
// Vertex Shader entry point
void main()
{
//
v_lightDir = normalize( gl_LightSource[0].position.xyz );
v_halfVec = normalize( gl_LightSource[0].halfVector.xyz );

//
gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
gl_Position = gl_Vertex;
}

Now for where the magic happens, the fragment shader, it uses two textures. The ‘baseImage‘ sampler is for the colour buffer, whilst the ‘nrmImage‘ is used for the normal texture we wrote…

//
// Uniform Variables
uniform sampler2D baseImage;
uniform sampler2D nrmImage;

//
// Varying Variables
varying vec3 v_lightDir;
varying vec3 v_halfVec;

//
// Fragment Shader entry point
void main()
{
// Get texel colour and normal data
vec4 kTexelColour = texture2D( baseImage, gl_TexCoord[0].xy );
vec4 kNormalColour = texture2D( nrmImage, gl_TexCoord[0].xy );

// Don't Perform Lighting on a non-lit texel
if( kNormalColour.w == 0.0 )
{
gl_FragData[0] = kTexelColour;
return;
}

// Calculate Ambient
vec4 kAmbient = gl_LightSource[0].ambient * kTexelColour;

// Process Light Direction and Normals
float NdotL = max( dot( kNormalColour.xyz, v_lightDir ), 0.0 );
vec4 kColour = kAmbient;

// Add Diffuse and Specular is NdotL is greater than zero
if( NdotL > 0.0 )
{
// Calculate Diffuse
vec4 kDiffuse = ( 1.0 - kAmbient ) * ( gl_LightSource[0].diffuse * kTexelColour );
vec4 kSpecular = gl_LightSource[0].specular;
float kShininess = 60.0;

float NdotHV = max( dot( kNormalColour.xyz, v_halfVec ), 0.0 );
kColour += kDiffuse * NdotL;
kColour += kSpecular * pow( NdotHV, kShininess );
}

// Write Pixel Colour
gl_FragData[0] = kColour;
}

As you can see, if the w component of the normal texture is 0.0 then the colour value is outputted as it is. If not, using the normal and the light currently setup, the colour is modified to be lit before being outputted.

I’ve just used a simple Blinn shader for calculating the lighting.

The Application

Now for the application side of things, below is just some quick sample code for what I used for my example. As you can see I’ve used a unsigned byte to store the normal, a floating point texture may have better accuracy at describing it though.

//
//
namespace CommonApp
{
enum TextureTypes
{
kColour,
kNormal,
kDepthStencil,
kNumTextureTypes,
};

//
const int kWidth = 800;
const int kHeight = 600;

//
GLuint l_frameBuffer;
GLuint l_textures[kNumTextureTypes];

//
GLuint l_colourProgram;
GLuint l_lightingProgram;
}

//
// Use alternate INTERNAL_FORMAT if floating point textures are not supported
//#define INTERNAL_FORMAT GL_RGBA
#define INTERNAL_FORMAT GL_RGBA32F_ARB

//
//
void CommonApp::Init()
{
// Code to load colouring shader program
// ...

// Code to load lighting shader program and setup uniform variables
// ...

// Generate Textures
glGenTextures( kNumTextureTypes, l_textures );

// Create Colour Texture
glBindTexture( GL_TEXTURE_2D, l_textures[kColour] );
glTexImage2D( GL_TEXTURE_2D, 0, INTERNAL_FORMAT, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Create Normal Texture
glBindTexture( GL_TEXTURE_2D, l_textures[kNormal] );
glTexImage2D( GL_TEXTURE_2D, 0, INTERNAL_FORMAT, kWidth, kHeight, 0, GL_RGBA, GL_FLOAT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Create Depth Buffer
glBindTexture( GL_TEXTURE_2D, l_textures[kDepthStencil] );
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8_EXT, kWidth, kHeight, 0, GL_DEPTH_STENCIL_EXT, GL_UNSIGNED_INT_24_8_EXT, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );

// Generate Framebuffer and attach textures
glGenFramebuffersEXT( 1, &l_frameBuffer );
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, l_frameBuffer );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, l_textures[kColour], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, l_textures[kNormal], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, l_textures[kDepthStencil], 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, l_textures[kDepthStencil], 0 );
}

//
//
void CommonApp::DeInit()
{
glDeleteFramebuffersEXT( 1, &l_frameBuffer );
glDeleteTextures( kNumTextureTypes, l_textures );
}

Just the usual code as you can see for setting up a frame buffer. Now for rendering the scene…

//
//
void CommonApp::Render()
{
// Use Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, l_frameBuffer );

// Set Draw Buffers
const GLenum kBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers( 2, kBuffers );

// Use Shading Program
glUseProgram( l_colourProgram );

// Perform Rendering
// ...

// Reset Draw Buffer
glDrawBuffer( GL_COLOR_ATTACHMENT0_EXT );

// Reset Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
}

I’ve set it up so that drawing to draw buffer zero writes to the colour texture, whilst drawing to draw buffer one writes to the normal texture, to reflect what is being done in the shader.

You don’t need to use the colour shader I described up above, as long as it writes out the normal and an unlit colour, any shader can be used for this process, but for demonstration I’ve made it in this example that all geometry is drawn with this shader program.

Finally with our scene rendered, we can moved onto the final post processing stage…

//
//
void CommonApp::PostRender()
{
glActiveTexture( GL_TEXTURE0 );
glBindTexture( GL_TEXTURE_2D, l_textures[kColour] );

glActiveTexture( GL_TEXTURE1 );
glBindTexture( GL_TEXTURE_2D, l_textures[kNormal] );

glUseProgram( l_lightingProgram );

// Render Fullscreen Quad
// ...
}

More Per-Pixel Directional Lighting through Post ProcessAttaching the colour and normal texture, using the per pixel lighting shader program and drawing a quad. The images within this blog are the final result (showing a comparison would be useless since they look the same).

One downside to this is that all texels have to use the same shininess value, however the alpha value of the colour buffer could be used to control this.

It is only a start, I need to performance check it at some point to see if it gives better or worse performance and under what conditions.

Download Source: Per Pixel Lighting (MacOSX)
Written by Kaluriel in: Athena, Code, Shaders, Tutorials | Tags: , ,
May
29
2009
0

Athena: More Uses for Framebuffer Objects

Depth Buffer using Frame Buffer ObjectAs I was upgrading my engine to the latest version of OpenGL, I noticed how my depth buffer was broken again (I use it for debugging my scenes when on the debug menu), and despite many changes, I was still having trouble getting it to display properly.

The glReadPixels() function with GL_DEPTH_COMPONENT was working, but I was having no luck at getting it displaying at any colour other than white without converting it first before writing it to a texture with glDrawPixels() – on reflection a floating point texture might have made this easier.

Anyways, when looking for answers, I found a way of using frame buffer objects to write out to multiple colour buffers, which allowed me to modify my Blinn shader to render a scene and the depth buffer to texture at the same time.

First of all, the shader needs to be shaders, instead of gl_FragColor, we use gl_FragData[n], where n is the index of the colour buffer we want to write to.

//
// Varying Variables
varying float v_farPlane;
varying float v_nearPlane;

//
// Fragment Shader entry point
void main()
{
// Write Pixel Colour
//gl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );
gl_FragData[0] = vec4( 1.0, 0.0, 0.0, 1.0 );

// Write Depth
float kDepth = 1.0 - ( gl_FragCoord.z / gl_FragCoord.w ) / ( v_farPlane - v_nearPlane );
gl_FragData[1] = vec4( kDepth, kDepth, kDepth, 1.0 ); // Luminace style
}

And finally when binding your frame buffer object.

//
//
void RenderTarget::Setup()
{
// Create Frame Buffer
glGenBuffers( 1, &m_frameBuffer );

// Bind Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_frameBuffer );

// Attach texture to receive colour
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, m_colorTexture, 0 );

// Attach Texture to receive depth buffer
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_2D, m_depthTexture, 0 );

// Attach Depth and Stencil Buffer (same object since my gfx card doesn't support them being seperate)
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, m_stencilDepthBuffer, 0 );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_STENCIL_ATTACHMENT_EXT, GL_TEXTURE_2D, m_stencilDepthBuffer, 0 );
}

//
//
void RenderTarget::StartRender()
{
// Bind Frame Buffer
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, m_frameBuffer );

// Set which index draws to which colour attachment
const GLenum kBuffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT };
glDrawBuffers( 2, kBuffers );
}

The call to glDrawBuffers() sets where gl_FragData[x] is being wrote to, I’ve specified there are two indexes, the first one points to colour attachment 0, and the second points to colour attachment 1.

Now when an object is rendered using that shader, it will output the normal colour buffer to colour attachment 0, and output the depth buffer to colour attachment 1.

Also, don’t forget to reset the draw buffer destination after you’re finished with it.

//
//
void RenderTarget::EndRender()
{
// Reset draw buffer destination
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);

// Unbind frame buffer and all attachments
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
}

I will probably remove the glBindFramebufferEXT() call to unbind the frame buffer at some point, so that the same frame buffer gets used for all render targets, only the attachments get changed.

I’ve read it is faster this way. For more information on this, there is this great article on GameDev.net about it called, OpenGL Frame Buffer Object 201.

I probably won’t use this for writing out the depth buffer, but it did give me some ideas for per pixel lighting.

Written by Kaluriel in: Athena, Code, Shaders, Tutorials | Tags: , , ,
May
28
2009
0

Athena: OpenGL 3.0 Upgrade in Progress…

Building in progress...

I just upgraded to the latest version of gDEBugger, and it kept notifying me that a lot of my code is using deprecated functions as of OpenGL 3.0.

So I have begun the long task of converting code and shaders alike, hopefully in a positive step since it will mean my DirectX 10 port of the Athena engine will have little modifications to work like the OpenGL and vice versa.

These functions are the first on my list, they are used for rendering my geometry.

glTexCoordPointer()

glColorPointer()

glNormalPointer()

glVertexPointer()

These have been replaced with glVertexAttribPointer(), a more useful system so you can specify custom attributes a vertex has, and link them to attribute variables in shaders (shaders are required now for everything like DirectX 10). So for a simple array of vertices, I linked them to attribute variable in my shader which was bound to location 0.

//
// Bind VBO Object
glBindBuffer( GL_ARRAY_BUFFER, m_vertexBuffer );

//
// Enable vertex attribute streaming on location 0
glEnableVertexAttribArray( 0 /* location */ );

//
// Set attribute offset, size, and type details for location 0
glVertexAttribPointer( 0, /* location */
4, /* components */
GL_FLOAT, /* type */
GL_FALSE, /* normalize */
sizeof( float ) * 4, /* stride */
0 ); /* buffer offset */

I found out shortly after however that the index I was using for my vertex attribute is a reserved index by nVidia for their built-in attributes, as are 12 others.

0 – gl_Vertex
2 – gl_Normal
3 – gl_Color
4 – gl_SecondaryColor
5 – gl_FogCoord
8 – gl_MultiTexCoord0
9 – gl_MultiTexCoord1
10 – gl_MultiTexCoord2
11 – gl_MultiTexCoord3
12 – gl_MultiTexCoord4
13 – gl_MultiTexCoord5
14 – gl_MultiTexCoord6
15 – gl_MultiTexCoord7

So in the interest of keeping things sane I changed the location index to be 16, all that was needed was updating my shaders to use attributes rather than gl_Position, etc.

//
// Vertex Attributes
attribute vec4 a_vertex;
attribute vec2 a_texCoord0;

//
// Vertex Shader Entry Point
void main()
{
//gl_TexCoord[0].xy = gl_MultiTexCoord0.xy;
gl_TexCoord[0].xy = a_texCoord0;

//gl_Position = gl_Vertex;
gl_Position = a_vertex;
}

You may have noticed that I don’t multiply my vertex by any transformation matrices, this is because my vertex coordinates for 2D are always in the range of -1.0 to 1.0. Doing it this way saves me changing projection matrix states whenever I want to draw 2D, so my projection matrix is always setup for 3D. Also, the source for this vertex shader program contains another attribute for the texture coordinate as well since I just copy-pasta’d my Bloom shader.

Now just two simple calls were needed to be added to my  shader program before it was linked, so that the vertex attribute is bound to the correct location.

glBindAttribLocation( m_program, 16 /* location */, "a_vertex" );
glBindAttribLocation( m_program, 17 /* location */, "a_texCoord0" );
glLinkProgram( m_program );

As you can see my vertex shader has a texture coordinate as well (I’m using my Bloom vertex shader as an example), so the final code for setting up the VBO for this is.

//
// VBO layout
struct TexturedVertex
{
float texCoord[2];
float position[4];
};

//
// Bind VBO Object
glBindBuffer( GL_ARRAY_BUFFER, myVBO );

//
// Enable vertex attribute streaming on location 0
glEnableVertexAttribArray( 16 );
glEnableVertexAttribArray( 17 );

//
// Set attribute offset, size, and type details for location 0
glVertexAttribPointer( 17, 2, GL_FLOAT, GL_FALSE, sizeof( TexturedVertex ), 0 );
glVertexAttribPointer( 16, 4, GL_FLOAT, GL_FALSE, sizeof( TexturedVertex ), sizeof( float ) * 2 );

I’m sure there is a preprocessor command to get the offset of a variable within a structure, but “sizeof( float ) * 2″ works as well. My code is a bit more complex than is shown here (I have a vertex format class that manages what needs to be set where, and something to managed state changes et cetera), but you get the idea of how it all works.

Well that was one big change down, on the next page of this blog entry will be another big change, replacing glMatrixMode() and glLoadMatrix().

Written by Kaluriel in: Athena, Code, Shaders | Tags: , ,

Pages: 1 2 3


Theme: TheBuckmaker.com Blog Themes | The best Webhosting Plans, Eigenes Internet Radio