3.3. Drawing a rectangle with a custom texture

This section describes how to draw a rectangle and apply a custom texture:

  1. Locate the tutorial project 07 - Texturing and open the main.cpp file.

  2. Example 3.1 shows the standard includes and initialization:

    Example 3.14. Creating the context for the texture example

    #include <mde/mde.h>
    
    using namespace MDE;
    
    int main()
    {
    	try
    	{
    		Managed<System> system = create_system_backend();	
    		Managed<Context> context = system->createContext(320, 240);
    		#ifdef MDE_OS_PC_LINUX
    			Managed<Keyboard> keyboard = system->createKeyboard(context);
    		#else
    			Managed<Keyboard> keyboard = system->createKeyboard();
    		#endif
    		// Define the shader sources. Basic texturing shaders.
    		const char* vertexsource =
    			"attribute vec4 POSITION;\
    			attribute vec2 TEXCOORD0;\
    			varying vec2 texcoord;\
    			void main(void)\
    			{\
    			gl_Position = POSITION;\
    			texcoord = TEXCOORD0;\
    			}";
    
    		const char* fragmentsource =
    			"precision mediump float; \
    			varying vec2 texcoord;\
    			uniform sampler2D texture;\
    			void main(void)\
    			{\
    			gl_FragColor = texture2D(texture, texcoord);\
    			}";
    
    		// Create Shader and Program objects:
    		Managed<Shader> vertexshader = context->createShader(GL_VERTEX_SHADER, vertexsource);
    		Managed<Shader> fragmentshader = context->createShader(GL_FRAGMENT_SHADER, fragmentsource);
    		Managed<Program> program = context->createProgram(vertexshader, fragmentshader);
    		context->setProgram(program);
    ...
    

  3. A bit-mapped texture is typically read from a file rather than created in the application. This example however defines the texture data and uses it to create a new texture object as shown in Example 3.2:

    Example 3.15. Identity shaders

    ...
    		const int size = 8;
    		unsigned int textureData[size*size];
    		unsigned int color = 0xFFFFFFFF;
    		for(int y = 0; y < size; y++)
    		{
    			for(int x = 0; x < size; x++ )
    			{
    				color ^= 0xFFFFFF;
    				textureData[y*size+x] = color;
    			}
    			color ^= 0xFFFFFF;
    		}
    
            // create an empty texture named checkerBoard
    		Managed<Texture2D> checkerBoard = context->createTexture2D();
    		checkerBoard->setFilterMode(GL_NEAREST, GL_NEAREST);
    
            // use the textureData array to fill the texture
    		checkerBoard->buildMipmaps(0, size, size, GL_RGBA, textureData);  
    ...
    

    The MipMaps object is used, and the dimensions of the rendered shape and the texture source are different.

    Note

    • The checkboard texture is a 2D shape.

    • The fragmentshader texture sets the pixel value based on the value of a point in the 2D texture shape:

      gl_FragColor = texture2D(texture, texcoord);
      
  4. As with Example 3.9 which combined the vertex and color data in one array, the code in Example 3.16 combines the vertices and texture locations:

    Example 3.16. Specifying the location for the shape and texture

    ...
    		GLfloat vertexData[24] = 
    		{ 
    			// X     Y     U      V
    			-1.0f, -1.0f, 0.0f, 0.0f,   // values for each vertex of the first triangle
    			 1.0f, -1.0f, 1.0f, 0.0f, 
    			-1.0f,  1.0f, 0.0f, 1.0f, 
    			 1.0f, -1.0f, 1.0f, 0.0f,  // values for each vertex of the second triangle
    			 1.0f,  1.0f, 1.0f, 1.0f, 
    			-1.0f,  1.0f, 0.0f, 1.0f
    		};
    
    		/* Set up the vertex buffer */
    		Managed<Buffer> vertexBuffer = context->createBuffer(GL_ARRAY_BUFFER, sizeof(vertexData),
                                           sizeof(GLfloat)*4);
    		vertexBuffer->setData(0, sizeof(vertexData), vertexData);
    ...
    

  5. The second element in the elements array is defined, and the semantic attribute is TECOORD0. See Example 3.3:

    Example 3.17. Setting VertexElement to use a texture

    ...
    		VertexElement elements[2];
    		elements[0].components = 2;                // xy position
    		elements[0].offset = 0;
    		elements[0].semantic = POSITION;           // this element is the vertices for the shapes
    		elements[0].stream = 0;
    		elements[0].type = GL_FLOAT;             
    		elements[1].components = 2;               // uv position
    		elements[1].offset = 2*sizeof(GLfloat);
    		elements[1].semantic = TEXCOORD0;         // this element is texture information
    		elements[1].stream = 0;
    		elements[1].type = GL_FLOAT;
    
            Managed<VertexDeclaration> vertexDeclaration = context->createVertexDeclaration(elements, 2);
    		context->setVertexDeclaration(vertexDeclaration);
    ...
    

  6. The shape and texture have been defined, so draw the shape as shown in Example 3.18.

    Example 3.18. Draw a shape with a custom texture

    ...
    		do
    		{
    			glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
    			glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
    			context->setVertexBuffer(0, vertexBuffer);
    
    			/*
    			* When dealing with 2D textures and shaders, we need to assign the texture to a sampler.
    			*/
    			context->setUniformSampler("texture", (Texture*)checkerBoard);
    
    			context->drawArrays( GL_TRIANGLES, 0, 2 );
    			if(keyboard->getSpecialKeyState(Keyboard::KEY_ESCAPE)) break;
    		}while( context->update() );
    
    	}
    	catch(Exception& e)
    	{
    		printf("MDE Exception: \n%s\n\n",e.getMessage().getCharString());
    	}
    }
    

  7. Figure 3.5 shows the shape with its texture:

    Figure 3.5. A custom texture on a 2D shape

    A custom texture on a 2D shape

Copyright © 2010 ARM. All rights reserved.ARM DUI 0527A‑02a
Non-Confidential - Draft - BetaID070710