Home | History | Annotate | Download | only in MipMap2D
      1 //
      2 // Book:      OpenGL(R) ES 2.0 Programming Guide
      3 // Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
      4 // ISBN-10:   0321502795
      5 // ISBN-13:   9780321502797
      6 // Publisher: Addison-Wesley Professional
      7 // URLs:      http://safari.informit.com/9780321563835
      8 //            http://www.opengles-book.com
      9 //
     10 
     11 // MipMap2D.c
     12 //
     13 //    This is a simple example that demonstrates generating a mipmap chain
     14 //    and rendering with it
     15 //
     16 #include <stdlib.h>
     17 #include "esUtil.h"
     18 
     19 typedef struct
     20 {
     21    // Handle to a program object
     22    GLuint programObject;
     23 
     24    // Attribute locations
     25    GLint  positionLoc;
     26    GLint  texCoordLoc;
     27 
     28    // Sampler location
     29    GLint samplerLoc;
     30 
     31    // Offset location
     32    GLint offsetLoc;
     33 
     34    // Texture handle
     35    GLuint textureId;
     36 
     37 } UserData;
     38 
     39 
     40 ///
     41 //  From an RGB8 source image, generate the next level mipmap
     42 //
     43 GLboolean GenMipMap2D( GLubyte *src, GLubyte **dst, int srcWidth, int srcHeight, int *dstWidth, int *dstHeight )
     44 {
     45    int x,
     46        y;
     47    int texelSize = 3;
     48 
     49    *dstWidth = srcWidth / 2;
     50    if ( *dstWidth <= 0 )
     51       *dstWidth = 1;
     52 
     53    *dstHeight = srcHeight / 2;
     54    if ( *dstHeight <= 0 )
     55       *dstHeight = 1;
     56 
     57    *dst = malloc ( sizeof(GLubyte) * texelSize * (*dstWidth) * (*dstHeight) );
     58    if ( *dst == NULL )
     59       return GL_FALSE;
     60 
     61    for ( y = 0; y < *dstHeight; y++ )
     62    {
     63       for( x = 0; x < *dstWidth; x++ )
     64       {
     65          int srcIndex[4];
     66          float r = 0.0f,
     67                g = 0.0f,
     68                b = 0.0f;
     69          int sample;
     70 
     71          // Compute the offsets for 2x2 grid of pixels in previous
     72          // image to perform box filter
     73          srcIndex[0] =
     74             (((y * 2) * srcWidth) + (x * 2)) * texelSize;
     75          srcIndex[1] =
     76             (((y * 2) * srcWidth) + (x * 2 + 1)) * texelSize;
     77          srcIndex[2] =
     78             ((((y * 2) + 1) * srcWidth) + (x * 2)) * texelSize;
     79          srcIndex[3] =
     80             ((((y * 2) + 1) * srcWidth) + (x * 2 + 1)) * texelSize;
     81 
     82          // Sum all pixels
     83          for ( sample = 0; sample < 4; sample++ )
     84          {
     85             r += src[srcIndex[sample]];
     86             g += src[srcIndex[sample] + 1];
     87             b += src[srcIndex[sample] + 2];
     88          }
     89 
     90          // Average results
     91          r /= 4.0;
     92          g /= 4.0;
     93          b /= 4.0;
     94 
     95          // Store resulting pixels
     96          (*dst)[ ( y * (*dstWidth) + x ) * texelSize ] = (GLubyte)( r );
     97          (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 1] = (GLubyte)( g );
     98          (*dst)[ ( y * (*dstWidth) + x ) * texelSize + 2] = (GLubyte)( b );
     99       }
    100    }
    101 
    102    return GL_TRUE;
    103 }
    104 
    105 ///
    106 //  Generate an RGB8 checkerboard image
    107 //
    108 GLubyte* GenCheckImage( int width, int height, int checkSize )
    109 {
    110    int x,
    111        y;
    112    GLubyte *pixels = malloc( width * height * 3 );
    113 
    114    if ( pixels == NULL )
    115       return NULL;
    116 
    117    for ( y = 0; y < height; y++ )
    118       for ( x = 0; x < width; x++ )
    119       {
    120          GLubyte rColor = 0;
    121          GLubyte bColor = 0;
    122 
    123          if ( ( x / checkSize ) % 2 == 0 )
    124          {
    125             rColor = 255 * ( ( y / checkSize ) % 2 );
    126             bColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
    127          }
    128          else
    129          {
    130             bColor = 255 * ( ( y / checkSize ) % 2 );
    131             rColor = 255 * ( 1 - ( ( y / checkSize ) % 2 ) );
    132          }
    133 
    134          pixels[(y * height + x) * 3] = rColor;
    135          pixels[(y * height + x) * 3 + 1] = 0;
    136          pixels[(y * height + x) * 3 + 2] = bColor;
    137       }
    138 
    139    return pixels;
    140 }
    141 
    142 ///
    143 // Create a mipmapped 2D texture image
    144 //
    145 GLuint CreateMipMappedTexture2D( )
    146 {
    147    // Texture object handle
    148    GLuint textureId;
    149    int    width = 256,
    150           height = 256;
    151    int    level;
    152    GLubyte *pixels;
    153    GLubyte *prevImage;
    154    GLubyte *newImage = NULL;
    155 
    156    pixels = GenCheckImage( width, height, 8 );
    157    if ( pixels == NULL )
    158       return 0;
    159 
    160    // Generate a texture object
    161    glGenTextures ( 1, &textureId );
    162 
    163    // Bind the texture object
    164    glBindTexture ( GL_TEXTURE_2D, textureId );
    165 
    166    // Load mipmap level 0
    167    glTexImage2D ( GL_TEXTURE_2D, 0, GL_RGB, width, height,
    168                   0, GL_RGB, GL_UNSIGNED_BYTE, pixels );
    169 
    170    level = 1;
    171    prevImage = &pixels[0];
    172 
    173    while ( width > 1 && height > 1 )
    174    {
    175       int newWidth,
    176           newHeight;
    177 
    178       // Generate the next mipmap level
    179       GenMipMap2D( prevImage, &newImage, width, height,
    180                    &newWidth, &newHeight );
    181 
    182       // Load the mipmap level
    183       glTexImage2D( GL_TEXTURE_2D, level, GL_RGB,
    184                     newWidth, newHeight, 0, GL_RGB,
    185                     GL_UNSIGNED_BYTE, newImage );
    186 
    187       // Free the previous image
    188       free ( prevImage );
    189 
    190       // Set the previous image for the next iteration
    191       prevImage = newImage;
    192       level++;
    193 
    194       // Half the width and height
    195       width = newWidth;
    196       height = newHeight;
    197    }
    198 
    199    free ( newImage );
    200 
    201    // Set the filtering mode
    202    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST );
    203    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
    204 
    205    return textureId;
    206 
    207 }
    208 
    209 
    210 ///
    211 // Initialize the shader and program object
    212 //
    213 int Init ( ESContext *esContext )
    214 {
    215    UserData *userData = esContext->userData;
    216    GLbyte vShaderStr[] =
    217       "uniform float u_offset;      \n"
    218       "attribute vec4 a_position;   \n"
    219       "attribute vec2 a_texCoord;   \n"
    220       "varying vec2 v_texCoord;     \n"
    221       "void main()                  \n"
    222       "{                            \n"
    223       "   gl_Position = a_position; \n"
    224       "   gl_Position.x += u_offset;\n"
    225       "   v_texCoord = a_texCoord;  \n"
    226       "}                            \n";
    227 
    228    GLbyte fShaderStr[] =
    229       "precision mediump float;                            \n"
    230       "varying vec2 v_texCoord;                            \n"
    231       "uniform sampler2D s_texture;                        \n"
    232       "void main()                                         \n"
    233       "{                                                   \n"
    234       "  gl_FragColor = texture2D( s_texture, v_texCoord );\n"
    235       "}                                                   \n";
    236 
    237    // Load the shaders and get a linked program object
    238    userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
    239 
    240    // Get the attribute locations
    241    userData->positionLoc = glGetAttribLocation ( userData->programObject, "a_position" );
    242    userData->texCoordLoc = glGetAttribLocation ( userData->programObject, "a_texCoord" );
    243 
    244    // Get the sampler location
    245    userData->samplerLoc = glGetUniformLocation ( userData->programObject, "s_texture" );
    246 
    247    // Get the offset location
    248    userData->offsetLoc = glGetUniformLocation( userData->programObject, "u_offset" );
    249 
    250    // Load the texture
    251    userData->textureId = CreateMipMappedTexture2D ();
    252 
    253    glClearColor ( 0.0f, 0.0f, 0.0f, 0.0f );
    254    return TRUE;
    255 }
    256 
    257 ///
    258 // Draw a triangle using the shader pair created in Init()
    259 //
    260 void Draw ( ESContext *esContext )
    261 {
    262    UserData *userData = esContext->userData;
    263    GLfloat vVertices[] = { -0.5f,  0.5f, 0.0f, 1.5f,  // Position 0
    264                             0.0f,  0.0f,              // TexCoord 0
    265                            -0.5f, -0.5f, 0.0f, 0.75f, // Position 1
    266                             0.0f,  1.0f,              // TexCoord 1
    267                             0.5f, -0.5f, 0.0f, 0.75f, // Position 2
    268                             1.0f,  1.0f,              // TexCoord 2
    269                             0.5f,  0.5f, 0.0f, 1.5f,  // Position 3
    270                             1.0f,  0.0f               // TexCoord 3
    271                          };
    272    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
    273 
    274    // Set the viewport
    275    glViewport ( 0, 0, esContext->width, esContext->height );
    276 
    277    // Clear the color buffer
    278    glClear ( GL_COLOR_BUFFER_BIT );
    279 
    280    // Use the program object
    281    glUseProgram ( userData->programObject );
    282 
    283    // Load the vertex position
    284    glVertexAttribPointer ( userData->positionLoc, 4, GL_FLOAT,
    285                            GL_FALSE, 6 * sizeof(GLfloat), vVertices );
    286    // Load the texture coordinate
    287    glVertexAttribPointer ( userData->texCoordLoc, 2, GL_FLOAT,
    288                            GL_FALSE, 6 * sizeof(GLfloat), &vVertices[4] );
    289 
    290    glEnableVertexAttribArray ( userData->positionLoc );
    291    glEnableVertexAttribArray ( userData->texCoordLoc );
    292 
    293    // Bind the texture
    294    glActiveTexture ( GL_TEXTURE0 );
    295    glBindTexture ( GL_TEXTURE_2D, userData->textureId );
    296 
    297    // Set the sampler texture unit to 0
    298    glUniform1i ( userData->samplerLoc, 0 );
    299 
    300    // Draw quad with nearest sampling
    301    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
    302    glUniform1f ( userData->offsetLoc, -0.6f );
    303    glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
    304 
    305    // Draw quad with trilinear filtering
    306    glTexParameteri ( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR );
    307    glUniform1f ( userData->offsetLoc, 0.6f );
    308    glDrawElements ( GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices );
    309 
    310    eglSwapBuffers ( esContext->eglDisplay, esContext->eglSurface );
    311 }
    312 
    313 ///
    314 // Cleanup
    315 //
    316 void ShutDown ( ESContext *esContext )
    317 {
    318    UserData *userData = esContext->userData;
    319 
    320    // Delete texture object
    321    glDeleteTextures ( 1, &userData->textureId );
    322 
    323    // Delete program object
    324    glDeleteProgram ( userData->programObject );
    325 }
    326 
    327 
    328 int main ( int argc, char *argv[] )
    329 {
    330    ESContext esContext;
    331    UserData  userData;
    332 
    333    esInitContext ( &esContext );
    334    esContext.userData = &userData;
    335 
    336    esCreateWindow ( &esContext, TEXT("MipMap 2D"), 320, 240, ES_WINDOW_RGB );
    337 
    338    if ( !Init ( &esContext ) )
    339       return 0;
    340 
    341    esRegisterDrawFunc ( &esContext, Draw );
    342 
    343    esMainLoop ( &esContext );
    344 
    345    ShutDown ( &esContext );
    346 }
    347