OpenGL Application Code in relation to GLSL

I am having some difficulty understanding the connection between my OpenGL application and my GLSL files (.vert and .frag). I know how to create a vertex or fragment shader, and there is plenty of examples on the web, but I am having difficulty actually using my shader within my application, specifically, linking (binding?) textures to my shader. My question is, what code am I missing to use the textures I have uploaded into my application with the shader?

My current application creates a window, loads 4 textures (rock, grass, stone, and a mixmap since I want to use this for texture splatting), and then draws a quad in the main loop. My entire code for the application is below:

#include <windows.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <SFML/Graphics.hpp>
#include <glew.h>
#include <gl/gl.h>
#include <gl/glu.h>

#include "textfile.h"
#include "textfile.cpp"

using namespace std;

class Scene {
public:
    void resize( int w, int h ) {
        // OpenGL Reshape
        glViewport( 0, 0, w, h );
        glMatrixMode( GL_PROJECTION );
        glLoadIdentity();
        gluPerspective( 120.0, (GLdouble)w/(GLdouble)h, 0.5, 500.0 );
        glMatrixMode( GL_MODELVIEW );
    }
};

///Shader
GLuint p, f, v;
void setShader() {

    char *vs,*fs;

    v = glCreateShader(GL_VERTEX_SHADER);
    f = glCreateShader(GL_FRAGMENT_SHADER);

    vs = textFileRead("shader.vert");
    fs = textFileRead("shader.frag");

    const char * vv = vs;
    const char * ff = fs;

    glShaderSource(v, 1, &vv,NULL);
    glShaderSource(f, 1, &ff,NULL);

    free(vs);free(fs);

    glCompileShader(v);
    glCompileShader(f);

    p = glCreateProgram();

    glAttachShader(p,v);
    glAttachShader(p,f);

    glLinkProgram(p);
    glUseProgram(p);
}

int main() {

    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Test");

    ///Setup the scene, materials, lighting
    Scene scene;
    scene.resize(800,600);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHTING);
    glColorMaterial(GL_FRONT_AND_BACK, GL_EMISSION);
    glEnable(GL_COLOR_MATERIAL);
    glShadeModel(GL_SMOOTH);

    ///Terrain Textures
    sf::Image tex0;
    tex0.loadFromFile("mixmap.png");
    sf::Image tex1;
    tex1.loadFromFile("grass.png");
    sf::Image tex2;
    tex2.loadFromFile("rock.png");
    sf::Image tex3;
    tex3.loadFromFile("stone.png");

    GLuint mixmap;
    glGenTextures(1, &mixmap);
    glBindTexture(GL_TEXTURE_2D, mixmap);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tex0.getSize().x, tex0.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)tex0.getPixelsPtr() );

    GLuint grass;
    glGenTextures(1, &grass);
    glBindTexture(GL_TEXTURE_2D, grass);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tex1.getSize().x, tex1.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)tex1.getPixelsPtr() );

    GLuint rock;
    glGenTextures(1, &rock);
    glBindTexture(GL_TEXTURE_2D, rock);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tex2.getSize().x, tex2.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)tex2.getPixelsPtr() );

    GLuint stone;
    glGenTextures(1, &stone);
    glBindTexture(GL_TEXTURE_2D, stone);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
    glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tex3.getSize().x, tex3.getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid*)tex3.getPixelsPtr() );

    ///I am afrain I am missing some code here that will actually link the textures to the shader itself

    ///Shader
    glewInit();
    setShader();

    ///Start loop
    while( window.isOpen() ) {
        sf::Event event;
        while( window.pollEvent( event ) ) {
            if( event.type == sf::Event::Closed )
                window.close();
        }

        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(50.0, 1.0, 1.0, 50);
        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(1, 0, 1, 0, 0, 0, 0, 1, 0);

        glBegin(GL_QUADS);
            glVertex3f(-0.5, -0.5, 0.0);

            glVertex3f(-0.5, 0.5, 0.0);

            glVertex3f(0.5, 0.5, 0.0);

            glVertex3f(0.5, -0.5, 0.0);
        glEnd();

        ///Reset env settings for SFML
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

        window.display();
    }
    return 1;
}

Below are my vertex and fragment shaders as well, though I am unsure if my vertex shader is complete...

Vertex:

void main()
{
 gl_TexCoord[0] = gl_MultiTexCoord0;
 gl_Position = ftransform();
} 

Fragment:

uniform sampler2D MixMap;
uniform sampler2D Grass;
uniform sampler2D Stone;
uniform sampler2D Rock;

varying vec4 texCoord;

void main(void)
{
   vec4 mixmap   = texture2D( MixMap, texCoord.xy );
   vec4 tex0    = texture2D( Grass, texCoord.xy ); 
   vec4 tex1    = texture2D( Rock,  texCoord.xy ); 
   vec4 tex2    = texture2D( Stone, texCoord.xy );

   tex0 *= mixmap.r; 
   tex1 = mix( tex0, tex1, mixmap.g ); 
   vec4 outColor = mix( tex1, tex2, mixmap.b ); 

   gl_FragColor = outColor;
}

Answers


First, you'll need to bind each texture object to a texture unit in the OpenGL context. GPUs have GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS number of texture image units, each of which can have textures attached to it.

This would look like this:

glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_2D, mixmap); //mixmap now attached to sampler 0

glActiveTexture(GL_TEXTURE0 + 1);
glBindTexture(GL_TEXTURE_2D, grass); //attached to sampler 1

glActiveTexture(GL_TEXTURE0 + 2);
glBindTexture(GL_TEXTURE_2D, rock);  //attached to sampler 2

glActiveTexture(GL_TEXTURE0 + 3);
glBindTexture(GL_TEXTURE_2D, stone); //attached to sampler 3

Note the GL_TEXTURE0 + x syntax. This is done so that you don't feel constrained by GL_TEXTUREi only going up to GL_TEXTURE32; you can have more than 32 simultaneous multi-textures (if your implementation supports it). Granted, I don't know why you would want to, but you can.

Now you have four textures bound to four texture image units. The next step is to assign the GLSL samplers to texture image units. After you have linked your shader, you must query the uniform location of each sampler, and then tell the program which texture image unit it should look for for the actual texture.

compileAndLinkProgram();
glUseProgram(program);

mixmapUniformLocation = glGetUniformLocation(program, "MixMap"); //get the uniform associated with "MixMap"
glUniform1i(mixmapUniformLocation, 0); //set MixMap uniform to 0 (sampler 0);


grassUniformLocation = glGetUniformLocation(program, "Grass"); //get the uniform associated with "Grass"
glUniform1i(grassUniformLocation, 1); //set Grass uniform to 1 (sampler 1);

...repeat for 4 samplers...

Now when you sample a sampler in the shader, it will pull from the texture bound to that sampler.


Need Your Help

OpenCL doesn't find ATI card

c++ opencl gpu-programming ati

I have a notebook with ATI Mobility Radeon HD 5650, and want to use the card for computing =) After installing AMD APP SDK v.2 (installation was OK) I tried to run code samples, provided with AMD. ...

Symfony, not whole form cleared

php symfony2

I have a problem with my registration form, when i click the submit button the registration is done, but not all values of the form are cleared, the password field always have 3 dots in it. What co...

About UNIX Resources Network

Original, collect and organize Developers related documents, information and materials, contains jQuery, Html, CSS, MySQL, .NET, ASP.NET, SQL, objective-c, iPhone, Ruby on Rails, C, SQL Server, Ruby, Arrays, Regex, ASP.NET MVC, WPF, XML, Ajax, DataBase, and so on.