diff options
Diffstat (limited to 'samples/gles2_book/MipMap2D/MipMap2D.c')
-rw-r--r-- | samples/gles2_book/MipMap2D/MipMap2D.c | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/samples/gles2_book/MipMap2D/MipMap2D.c b/samples/gles2_book/MipMap2D/MipMap2D.c new file mode 100644 index 00000000..bc70cd4c --- /dev/null +++ b/samples/gles2_book/MipMap2D/MipMap2D.c @@ -0,0 +1,346 @@ +// +// Book: OpenGL(R) ES 2.0 Programming Guide +// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner +// ISBN-10: 0321502795 +// ISBN-13: 9780321502797 +// Publisher: Addison-Wesley Professional +// URLs: http://safari.informit.com/9780321563835 +// http://www.opengles-book.com +// + +// MipMap2D.c +// +// This is a simple example that demonstrates generating a mipmap chain +// and rendering with it +// +#include <stdlib.h> +#include "esUtil.h" + +typedef struct +{ + // Handle to a program object + GLuint programObject; + + // Attribute locations + GLint positionLoc; + GLint texCoordLoc; + + // Sampler location + GLint samplerLoc; + + // Offset location + GLint offsetLoc; + + // Texture handle + GLuint textureId; + +} UserData; + + +/// +// From an RGB8 source image, generate the next level mipmap +// +GLboolean GenMipMap2D( GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight ) +{ + int x, + y; + int texelSize = 3; + + *dstWidth = srcWidth / 2; + if ( *dstWidth <= 0 ) + *dstWidth = 1; + + *dstHeight = srcHeight / 2; + if ( *dstHeight <= 0 ) + *dstHeight = 1; + + *dst = malloc ( sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight) ); + if ( *dst == NULL ) + return GL_FALSE; + + for ( y = 0; y < *dstHeight; y++ ) + { + for( x = 0; x < *dstWidth; x++ ) + { + int srcIndex[4]; + float r = 0.0f, + g = 0.0f, + b = 0.0f; + int sample; + + // Compute the offsets for 2x2 grid of pixels in previous + // image to perform box filter + srcIndex[0] = + (((y * 2) * srcWidth) + (x * 2)) * texelSize; + srcIndex[1] = + (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize; + srcIndex[2] = + ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize; + srcIndex[3] = + ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize; + + // Sum all pixels + for ( sample = 0; sample < 4; sample++ ) + { + r += src[srcIndex[sample]]; + g += src[srcIndex[sample] + 1]; + b += src[srcIndex[sample] + 2]; + } + + // Average results + r /= 4.0; + g /= 4.0; + b /= 4.0; + + // Store resulting pixels + (*dst)[ ( y * (*dstWidth) + x ) * texelSize ] = (GLubyte)( r ); + (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 1] = (GLubyte)( g ); + (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 2] = (GLubyte)( b ); + } + } + + return GL_TRUE; +} + +/// +// Generate an RGB8 checkerboard image +// +GLubyte* GenCheckImage( int width, int height, int checkSize ) +{ + int x, + y; + GLubyte *pixels = malloc( width * height * 3 ); + + if ( pixels == NULL ) + return NULL; + + for ( y = 0; y < height; y++ ) + for ( x = 0; x < width; x++ ) + { + GLubyte rColor = 0; + GLubyte bColor = 0; + + if ( ( x / checkSize ) % 2 == 0 ) + { + rColor = 255 * ( ( y / checkSize ) % 2 ); + bColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) ); + } + else + { + bColor = 255 * ( ( y / checkSize ) % 2 ); + rColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) ); + } + + pixels[(y * height + x) * 3] = rColor; + pixels[(y * height + x) * 3 + 1] = 0; + pixels[(y * height + x) * 3 + 2] = bColor; + } + + return pixels; +} + +/// +// Create a mipmapped 2D texture image +// +GLuint CreateMipMappedTexture2D( ) +{ + // Texture object handle + GLuint textureId; + int width = 256, + height = 256; + int level; + GLubyte *pixels; + GLubyte *prevImage; + GLubyte *newImage = NULL; + + pixels = GenCheckImage( width, height, 8 ); + if ( pixels == NULL ) + return 0; + + // Generate a texture object + glGenTextures ( 1, &textureId ); + + // Bind the texture object + glBindTexture ( GL_TEXTURE_2D, textureId ); + + // Load mipmap level 0 + glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height, + 0, GL_RGB, GL_UNSIGNED_BYTE, pixels ); + + level = 1; + prevImage = &pixels[0]; + + while ( width > 1 && height > 1 ) + { + int newWidth, + newHeight; + + // Generate the next mipmap level + GenMipMap2D( prevImage, &newImage, width, height, + &newWidth, &newHeight ); + + // Load the mipmap level + glTexImage2D( GL_TEXTURE_2D, level, GL_RGB, + newWidth, newHeight, 0, GL_RGB, + GL_UNSIGNED_BYTE, newImage ); + + // Free the previous image + free ( prevImage ); + + // Set the previous image for the next iteration + prevImage = newImage; + level++; + + // Half the width and height + width = newWidth; + height = newHeight; + } + + free ( newImage ); + + // Set the filtering mode + glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST ); + glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + + return textureId; + +} + + +/// +// Initialize the shader and program object +// +int Init ( ESContext *esContext ) +{ + UserData *userData = esContext->userData; + GLbyte vShaderStr[] = + "uniform float u_offset; \n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position; \n" + " gl_Position.x += u_offset;\n" + " v_texCoord = a_texCoord; \n" + "} \n"; + + GLbyte fShaderStr[] = + "precision mediump float; \n" + "varying vec2 v_texCoord; \n" + "uniform sampler2D s_texture; \n" + "void main() \n" + "{ \n" + " gl_FragColor = texture2D( s_texture, v_texCoord );\n" + "} \n"; + + // Load the shaders and get a linked program object + userData->programObject = esLoadProgram ( vShaderStr, fShaderStr ); + + // Get the attribute locations + userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" ); + userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" ); + + // Get the sampler location + userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" ); + + // Get the offset location + userData->offsetLoc = glGetUniformLocation( userData->programObject, "u_offset" ); + + // Load the texture + userData->textureId = CreateMipMappedTexture2D (); + + glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f ); + return TRUE; +} + +/// +// Draw a triangle using the shader pair created in Init() +// +void Draw ( ESContext *esContext ) +{ + UserData *userData = esContext->userData; + GLfloat vVertices[] = { -0.5f, 0.5f, 0.0f, 1.5f, // Position 0 + 0.0f, 0.0f, // TexCoord 0 + -0.5f, -0.5f, 0.0f, 0.75f, // Position 1 + 0.0f, 1.0f, // TexCoord 1 + 0.5f, -0.5f, 0.0f, 0.75f, // Position 2 + 1.0f, 1.0f, // TexCoord 2 + 0.5f, 0.5f, 0.0f, 1.5f, // Position 3 + 1.0f, 0.0f // TexCoord 3 + }; + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + // Set the viewport + glViewport ( 0, 0, esContext->width, esContext->height ); + + // Clear the color buffer + glClear ( GL_COLOR_BUFFER_BIT ); + + // Use the program object + glUseProgram ( userData->programObject ); + + // Load the vertex position + glVertexAttribPointer ( userData->positionLoc, 4, GL_FLOAT, + GL_FALSE, 6 * sizeof(GLfloat), vVertices ); + // Load the texture coordinate + glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT, + GL_FALSE, 6 * sizeof(GLfloat), &vVertices[4] ); + + glEnableVertexAttribArray ( userData->positionLoc ); + glEnableVertexAttribArray ( userData->texCoordLoc ); + + // Bind the texture + glActiveTexture ( GL_TEXTURE0 ); + glBindTexture ( GL_TEXTURE_2D, userData->textureId ); + + // Set the sampler texture unit to 0 + glUniform1i ( userData->samplerLoc, 0 ); + + // Draw quad with nearest sampling + glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glUniform1f ( userData->offsetLoc, -0.6f ); + glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); + + // Draw quad with trilinear filtering + glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); + glUniform1f ( userData->offsetLoc, 0.6f ); + glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices ); + + eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface ); +} + +/// +// Cleanup +// +void ShutDown ( ESContext *esContext ) +{ + UserData *userData = esContext->userData; + + // Delete texture object + glDeleteTextures ( 1, &userData->textureId ); + + // Delete program object + glDeleteProgram ( userData->programObject ); +} + + +int main ( int argc, char *argv[] ) +{ + ESContext esContext; + UserData userData; + + esInitContext ( &esContext ); + esContext.userData = &userData; + + esCreateWindow ( &esContext, TEXT("MipMap 2D"), 320, 240, ES_WINDOW_RGB ); + + if ( !Init ( &esContext ) ) + return 0; + + esRegisterDrawFunc ( &esContext, Draw ); + + esMainLoop ( &esContext ); + + ShutDown ( &esContext ); +} |