SDL OpenGL Textures

Notes:

Since the ACTUAL lesson about Texture Buffer Objects was completely deprecated I went ahead and made sure we could load our textures with SDL2.
Make sure to have SDL2 insalled on your system and add -lSDL2_image to your Makefile.

Vertex Shader:

#version 330 core
 
// Incoming per vertex... position and normal
in vec4 vVertex;
in vec4 vTexture;

uniform mat4	mvpMatrix;
uniform mat4	mvMatrix;

smooth out vec2 vTexCoords;

void main(void) 
{ 
    // Pass along the texture coordinates
    vTexCoords = vTexture.st;

    // Transform the geometry
    gl_Position = mvpMatrix * vVertex;
}

Fragment Shader:

#version 330 core

out vec4 vFragColor;

uniform sampler2D uTexture; 

smooth in vec2 vTexCoords;

void main(void)
{ 
    // The texture
    vFragColor = texture(uTexture, vTexCoords);
}

Source:

// SDLTexture.cpp
// Load our textures with SDL2

#include <stdio.h>
#include <GLTools.h>	// OpenGL toolkit
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_opengl.h>
#include <SDL2/SDL_image.h>
#include <GLMatrixStack.h>
#include <GLFrame.h>
#include <GLFrustum.h>
#include <GLBatch.h>
#include <GLGeometryTransform.h>

const int SCREEN_WIDTH = 480;
const int SCREEN_HEIGHT = 480;

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//OpenGL context
SDL_GLContext gContext;

// Our SDL surface
SDL_Surface *Surface;

// An assortment of needed classes
GLFrame             viewFrame;
GLFrustum			viewFrustum;
GLMatrixStack		modelViewMatrix;
GLMatrixStack		projectionMatrix;

GLGeometryTransform	transformPipeline;
GLShaderManager		shaderManager;

GLuint              textureShader;
GLuint              texture;
GLBatch             pyramidBatch;

GLint               locMVP;
GLint               locMV;
GLint               locTexture;

// Make our pyramid
void MakePyramid(GLBatch& pyramidBatch)
{
	pyramidBatch.Begin(GL_TRIANGLES, 18, 1);
    
	// Bottom of pyramid
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
    
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
	pyramidBatch.Vertex3f(1.0f, -1.0f, -1.0f);
    
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
	pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);
    
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 1.0f);
	pyramidBatch.Vertex3f(-1.0f, -1.0f, 1.0f);
    
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3f(-1.0f, -1.0f, -1.0f);
    
	pyramidBatch.Normal3f(0.0f, -1.0f, 0.0f);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 1.0f);
	pyramidBatch.Vertex3f(1.0f, -1.0f, 1.0f);
    
	
	M3DVector3f vApex = { 0.0f, 1.0f, 0.0f };
	M3DVector3f vFrontLeft = { -1.0f, -1.0f, 1.0f };
	M3DVector3f vFrontRight = { 1.0f, -1.0f, 1.0f };
	M3DVector3f vBackLeft = { -1.0f, -1.0f, -1.0f };
	M3DVector3f vBackRight = { 1.0f, -1.0f, -1.0f };
	M3DVector3f n;
	
	// Front of Pyramid
	m3dFindNormal(n, vApex, vFrontLeft, vFrontRight);
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
	pyramidBatch.Vertex3fv(vApex);		// Apex
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3fv(vFrontLeft);		// Front left corner
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
	pyramidBatch.Vertex3fv(vFrontRight);		// Front right corner
    
    
	m3dFindNormal(n, vApex, vBackLeft, vFrontLeft);
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
	pyramidBatch.Vertex3fv(vApex);		// Apex
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
	pyramidBatch.Vertex3fv(vBackLeft);		// Back left corner
	
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3fv(vFrontLeft);		// Front left corner
    
	m3dFindNormal(n, vApex, vFrontRight, vBackRight);
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
	pyramidBatch.Vertex3fv(vApex);				// Apex
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
	pyramidBatch.Vertex3fv(vFrontRight);		// Front right corner
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3fv(vBackRight);			// Back right cornder
    
    
	m3dFindNormal(n, vApex, vBackRight, vBackLeft);
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.5f, 1.0f);
	pyramidBatch.Vertex3fv(vApex);		// Apex
    
	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 0.0f, 0.0f);
	pyramidBatch.Vertex3fv(vBackRight);		// Back right cornder

	pyramidBatch.Normal3fv(n);
	pyramidBatch.MultiTexCoord2f(0, 1.0f, 0.0f);
	pyramidBatch.Vertex3fv(vBackLeft);		// Back left corner

	pyramidBatch.End();
}

// Load a TGA as a 2D Texture. Completely initialize the state
bool LoadTGATexture(const char *szFileName, GLenum minFilter, GLenum magFilter, GLenum wrapMode)
{
    Surface = IMG_Load(szFileName);
    if (Surface == NULL)
    {
        return false;
    }
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);

    int Mode = GL_BGR;              // data mode order

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
    
	glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

    glTexImage2D(GL_TEXTURE_2D,     // target
                 0,                 // base level
                 GL_RGB,            // internal mode
                 Surface->w, 
                 Surface->h, 
                 0,                 // border
                 Mode,              // image mode
                 GL_UNSIGNED_BYTE,  // type
                 Surface->pixels);  // data

	return true;
}

// This function does any needed initialization on the rendering context. 
// This is the first opportunity to do any OpenGL related tasks.
void SetupRC()
{
	//Initialize SDL
	if (SDL_Init(SDL_INIT_VIDEO) < 0)
	{
		printf("SDL could not initialize! SDL Error: %s\n", SDL_GetError());
	}
	else
	{
		//Use OpenGL 3.3 core
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
		SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);

		//Create window
		gWindow = SDL_CreateWindow("SDL2 Load Texture", 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SDL_WINDOWPOS_UNDEFINED, 
                                    SCREEN_WIDTH, 
                                    SCREEN_HEIGHT, 
                                    SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
		if(gWindow == NULL)
		{
			printf("Window could not be created! SDL Error: %s\n", SDL_GetError());
		}
		else
		{
			//Create context
			gContext = SDL_GL_CreateContext(gWindow);
			if(gContext == NULL)
			{
				printf("OpenGL context could not be created! SDL Error: %s\n", SDL_GetError());
			}
			else
			{
				//Initialize GLEW
				glewExperimental = GL_TRUE; 
				GLenum glewError = glewInit();
				if(glewError != GLEW_OK)
				{
					printf("Error initializing GLEW! %s\n", glewGetErrorString(glewError));
				}

				//Use Vsync
				if(SDL_GL_SetSwapInterval(1) < 0)
				{
					printf("Warning: Unable to set VSync! SDL Error: %s\n", SDL_GetError());
				}
			}
		}
	}
    // Grey background
    glClearColor(0.6f, 0.3f, 0.1f, 1.0f );

    // Enable depth testing
	glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glEnable(GL_TEXTURE_2D);

	viewFrame.MoveForward(8.0f);

    MakePyramid(pyramidBatch);

    // handle shaders
	shaderManager.InitializeStockShaders();
    textureShader = gltLoadShaderPairWithAttributes("glsl.vs",
                                                    "glsl.fs",
                                                    2,
                                                    GLT_ATTRIBUTE_VERTEX,
                                                    "vVertex",
                                                    GLT_ATTRIBUTE_TEXTURE0,
                                                    "vTexture");
    locMVP      = glGetUniformLocation(textureShader, "mvpMatrix");
    locMV       = glGetUniformLocation(textureShader, "mvMatrix");
    locTexture  = glGetUniformLocation(textureShader, "uTexture");

    // generate texture as normal
    LoadTGATexture("stone.tga", GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE);

    viewFrustum.SetPerspective(35.0f, SCREEN_WIDTH / SCREEN_HEIGHT, 1.0f, 100.f);
    projectionMatrix.LoadMatrix(viewFrustum.GetProjectionMatrix());
	transformPipeline.SetMatrixStacks(modelViewMatrix, projectionMatrix);
}

// Cleanup
void ShutdownRC(void)
{
    glDeleteTextures(1, &texture);
    SDL_DestroyWindow(gWindow);
    gWindow = NULL;
    SDL_Quit();
}

///////////////////////////////////////////////////////////////////////////////
// Called to draw scene
void RenderScene(void)
{    
	// Clear the window with current clearing color
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

	modelViewMatrix.PushMatrix(viewFrame);
        glBindTexture(GL_TEXTURE_2D, texture);
        // bind program
        glUseProgram(textureShader);
        // variables for shader
        glUniformMatrix4fv(locMVP, 1, GL_FALSE, transformPipeline.GetModelViewProjectionMatrix());
        glUniformMatrix4fv(locMV, 1, GL_FALSE, transformPipeline.GetModelViewMatrix());
        glUniform1i(locTexture, 0);
        // render
        pyramidBatch.Draw();
	modelViewMatrix.PopMatrix();
}

// Main entry point for GLUT based programs
int main(int argc, char* argv[])
{
    gltSetWorkingDirectory(argv[0]);
        
    SetupRC();

    SDL_Event event;
    bool running = true;
    while (running)
    {
        //Handle events on queue
        while(SDL_PollEvent(&event) != 0)
        {
            //User requests quit
            if(event.type == SDL_QUIT)
            {
                running = false;
            }
            if (event.type == SDL_KEYDOWN)
            {
                switch (event.key.keysym.sym)
                {
                    case SDLK_q:
                        running = false;
                        break;
                    case SDLK_LEFT:
                        viewFrame.RotateWorld(m3dDegToRad(-5.0f), 0.0f, 1.0f, 0.0f);
                        break;
                    case SDLK_RIGHT:
                        viewFrame.RotateWorld(m3dDegToRad( 5.0f), 0.0f, 1.0f, 0.0f);
                        break;
                    default:
                        break;
                }
            }
        }
        RenderScene();
        //Update screen
        SDL_GL_SwapWindow(gWindow);
    }
    ShutdownRC();

    return 0;
}

Answer:


Back to index