Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //--------------------------------------------------------------------------------
     18 // MoreTeapotsRenderer.cpp
     19 // Render teapots
     20 //--------------------------------------------------------------------------------
     21 //--------------------------------------------------------------------------------
     22 // Include files
     23 //--------------------------------------------------------------------------------
     24 #include "MoreTeapotsRenderer.h"
     25 
     26 //--------------------------------------------------------------------------------
     27 // Teapot model data
     28 //--------------------------------------------------------------------------------
     29 #include "teapot.inl"
     30 
     31 //--------------------------------------------------------------------------------
     32 // Ctor
     33 //--------------------------------------------------------------------------------
     34 MoreTeapotsRenderer::MoreTeapotsRenderer() :
     35                 geometry_instancing_support_( false )
     36 {
     37 
     38 }
     39 
     40 //--------------------------------------------------------------------------------
     41 // Dtor
     42 //--------------------------------------------------------------------------------
     43 MoreTeapotsRenderer::~MoreTeapotsRenderer()
     44 {
     45     Unload();
     46 }
     47 
     48 //--------------------------------------------------------------------------------
     49 // Init
     50 //--------------------------------------------------------------------------------
     51 void MoreTeapotsRenderer::Init( const int32_t numX,
     52         const int32_t numY,
     53         const int32_t numZ )
     54 {
     55     if( ndk_helper::GLContext::GetInstance()->GetGLVersion() >= 3.0 )
     56     {
     57         geometry_instancing_support_ = true;
     58     }
     59     else if( ndk_helper::GLContext::GetInstance()->CheckExtension( "GL_NV_draw_instanced" )
     60             && ndk_helper::GLContext::GetInstance()->CheckExtension(
     61                     "GL_NV_uniform_buffer_object" ) )
     62     {
     63         LOGI( "Supported via extension!" );
     64         //_bGeometryInstancingSupport = true;
     65         //_bARBSupport = true; //Need to patch shaders
     66         //Currently this has been disabled
     67     }
     68 
     69     //Settings
     70     glFrontFace( GL_CCW );
     71 
     72     //Create Index buffer
     73     num_indices_ = sizeof(teapotIndices) / sizeof(teapotIndices[0]);
     74     glGenBuffers( 1, &ibo_ );
     75     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo_ );
     76     glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(teapotIndices), teapotIndices, GL_STATIC_DRAW );
     77     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
     78 
     79     //Create VBO
     80     num_vertices_ = sizeof(teapotPositions) / sizeof(teapotPositions[0]) / 3;
     81     int32_t iStride = sizeof(TEAPOT_VERTEX);
     82     int32_t iIndex = 0;
     83     TEAPOT_VERTEX* p = new TEAPOT_VERTEX[num_vertices_];
     84     for( int32_t i = 0; i < num_vertices_; ++i )
     85     {
     86         p[i].pos[0] = teapotPositions[iIndex];
     87         p[i].pos[1] = teapotPositions[iIndex + 1];
     88         p[i].pos[2] = teapotPositions[iIndex + 2];
     89 
     90         p[i].normal[0] = teapotNormals[iIndex];
     91         p[i].normal[1] = teapotNormals[iIndex + 1];
     92         p[i].normal[2] = teapotNormals[iIndex + 2];
     93         iIndex += 3;
     94     }
     95     glGenBuffers( 1, &vbo_ );
     96     glBindBuffer( GL_ARRAY_BUFFER, vbo_ );
     97     glBufferData( GL_ARRAY_BUFFER, iStride * num_vertices_, p, GL_STATIC_DRAW );
     98     glBindBuffer( GL_ARRAY_BUFFER, 0 );
     99     delete[] p;
    100 
    101     //Init Projection matrices
    102     teapot_x_ = numX;
    103     teapot_y_ = numY;
    104     teapot_z_ = numZ;
    105     vec_mat_models_.reserve( teapot_x_ * teapot_y_ * teapot_z_ );
    106 
    107     UpdateViewport();
    108 
    109     const float total_width = 500.f;
    110     float gap_x = total_width / (teapot_x_ - 1);
    111     float gap_y = total_width / (teapot_y_ - 1);
    112     float gap_z = total_width / (teapot_z_ - 1);
    113     float offset_x = -total_width / 2.f;
    114     float offset_y = -total_width / 2.f;
    115     float offset_z = -total_width / 2.f;
    116 
    117     for( int32_t iX = 0; iX < teapot_x_; ++iX )
    118         for( int32_t iY = 0; iY < teapot_y_; ++iY )
    119             for( int32_t iZ = 0; iZ < teapot_z_; ++iZ )
    120             {
    121                 vec_mat_models_.push_back(
    122                         ndk_helper::Mat4::Translation( iX * gap_x + offset_x, iY * gap_y + offset_y,
    123                                 iZ * gap_z + offset_z ) );
    124                 vec_colors_.push_back(
    125                         ndk_helper::Vec3( random() / float( RAND_MAX * 1.1 ),
    126                                 random() / float( RAND_MAX * 1.1 ),
    127                                 random() / float( RAND_MAX * 1.1 ) ) );
    128 
    129                 float fX = random() / float( RAND_MAX ) - 0.5f;
    130                 float fY = random() / float( RAND_MAX ) - 0.5f;
    131                 vec_rotations_.push_back( ndk_helper::Vec2( fX * 0.05f, fY * 0.05f ) );
    132                 vec_current_rotations_.push_back( ndk_helper::Vec2( fX * M_PI, fY * M_PI ) );
    133             }
    134 
    135     if( geometry_instancing_support_ )
    136     {
    137         //
    138         //Create parameter dictionary for shader patch
    139         std::map<std::string, std::string> param;
    140         param[std::string( "%NUM_TEAPOT%" )] = ToString( teapot_x_ * teapot_y_ * teapot_z_ );
    141         param[std::string( "%LOCATION_VERTEX%" )] = ToString( ATTRIB_VERTEX );
    142         param[std::string( "%LOCATION_NORMAL%" )] = ToString( ATTRIB_NORMAL );
    143         if( arb_support_ )
    144             param[std::string( "%ARB%" )] = std::string( "ARB" );
    145         else
    146             param[std::string( "%ARB%" )] = std::string( "" );
    147 
    148         //Load shader
    149         bool b = LoadShadersES3( &shader_param_, "Shaders/VS_ShaderPlainES3.vsh",
    150                 "Shaders/ShaderPlainES3.fsh", param );
    151         if( b )
    152         {
    153             //
    154             //Create uniform buffer
    155             //
    156             GLuint bindingPoint = 1;
    157             GLuint blockIndex;
    158             blockIndex = glGetUniformBlockIndex( shader_param_.program_, "ParamBlock" );
    159             glUniformBlockBinding( shader_param_.program_, blockIndex, bindingPoint );
    160 
    161             //Retrieve array stride value
    162             int32_t iNumIndices;
    163             glGetActiveUniformBlockiv( shader_param_.program_, blockIndex,
    164                     GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &iNumIndices );
    165             GLint i[iNumIndices];
    166             GLint stride[iNumIndices];
    167             glGetActiveUniformBlockiv( shader_param_.program_, blockIndex,
    168                     GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, i );
    169             glGetActiveUniformsiv( shader_param_.program_, iNumIndices, (GLuint*) i,
    170                     GL_UNIFORM_ARRAY_STRIDE, stride );
    171 
    172             ubo_matrix_stride_ = stride[0] / sizeof(float);
    173             ubo_vector_stride_ = stride[2] / sizeof(float);
    174 
    175             glGenBuffers( 1, &ubo_ );
    176             glBindBuffer( GL_UNIFORM_BUFFER, ubo_ );
    177             glBindBufferBase( GL_UNIFORM_BUFFER, bindingPoint, ubo_ );
    178 
    179             //Store color value which wouldn't be updated every frame
    180             int32_t iSize = teapot_x_ * teapot_y_ * teapot_z_
    181                     * (ubo_matrix_stride_ + ubo_matrix_stride_ + ubo_vector_stride_); //Mat4 + Mat4 + Vec3 + 1 stride
    182             float* pBuffer = new float[iSize];
    183             float* pColor = pBuffer + teapot_x_ * teapot_y_ * teapot_z_ * ubo_matrix_stride_ * 2;
    184             for( int32_t i = 0; i < teapot_x_ * teapot_y_ * teapot_z_; ++i )
    185             {
    186                 memcpy( pColor, &vec_colors_[i], 3 * sizeof(float) );
    187                 pColor += ubo_vector_stride_; //Assuming std140 layout which is 4 DWORD stride for vectors
    188             }
    189 
    190             glBufferData( GL_UNIFORM_BUFFER, iSize * sizeof(float), pBuffer, GL_DYNAMIC_DRAW );
    191             delete[] pBuffer;
    192         }
    193         else
    194         {
    195             LOGI( "Shader compilation failed!! Falls back to ES2.0 pass" );
    196             //This happens some devices.
    197             geometry_instancing_support_ = false;
    198             //Load shader for GLES2.0
    199             LoadShaders( &shader_param_, "Shaders/VS_ShaderPlain.vsh", "Shaders/ShaderPlain.fsh" );
    200         }
    201     }
    202     else
    203     {
    204         //Load shader for GLES2.0
    205         LoadShaders( &shader_param_, "Shaders/VS_ShaderPlain.vsh", "Shaders/ShaderPlain.fsh" );
    206     }
    207 }
    208 
    209 void MoreTeapotsRenderer::UpdateViewport()
    210 {
    211     int32_t viewport[4];
    212     glGetIntegerv( GL_VIEWPORT, viewport );
    213     float fAspect = (float) viewport[2] / (float) viewport[3];
    214 
    215     const float CAM_NEAR = 5.f;
    216     const float CAM_FAR = 10000.f;
    217     bool bRotate = false;
    218     mat_projection_ = ndk_helper::Mat4::Perspective( fAspect, 1.f, CAM_NEAR, CAM_FAR );
    219 }
    220 
    221 //--------------------------------------------------------------------------------
    222 // Unload
    223 //--------------------------------------------------------------------------------
    224 void MoreTeapotsRenderer::Unload()
    225 {
    226     if( vbo_ )
    227     {
    228         glDeleteBuffers( 1, &vbo_ );
    229         vbo_ = 0;
    230     }
    231     if( ubo_ )
    232     {
    233         glDeleteBuffers( 1, &ubo_ );
    234         ubo_ = 0;
    235     }
    236     if( ibo_ )
    237     {
    238         glDeleteBuffers( 1, &ibo_ );
    239         ibo_ = 0;
    240     }
    241     if( shader_param_.program_ )
    242     {
    243         glDeleteProgram( shader_param_.program_ );
    244         shader_param_.program_ = 0;
    245     }
    246 }
    247 
    248 //--------------------------------------------------------------------------------
    249 // Update
    250 //--------------------------------------------------------------------------------
    251 void MoreTeapotsRenderer::Update( float fTime )
    252 {
    253     const float CAM_X = 0.f;
    254     const float CAM_Y = 0.f;
    255     const float CAM_Z = 2000.f;
    256 
    257     mat_view_ = ndk_helper::Mat4::LookAt( ndk_helper::Vec3( CAM_X, CAM_Y, CAM_Z ),
    258             ndk_helper::Vec3( 0.f, 0.f, 0.f ), ndk_helper::Vec3( 0.f, 1.f, 0.f ) );
    259 
    260     if( camera_ )
    261     {
    262         camera_->Update();
    263         mat_view_ = camera_->GetTransformMatrix() * mat_view_ * camera_->GetRotationMatrix();
    264     }
    265 }
    266 
    267 //--------------------------------------------------------------------------------
    268 // Render
    269 //--------------------------------------------------------------------------------
    270 void MoreTeapotsRenderer::Render()
    271 {
    272     // Bind the VBO
    273     glBindBuffer( GL_ARRAY_BUFFER, vbo_ );
    274 
    275     int32_t iStride = sizeof(TEAPOT_VERTEX);
    276     // Pass the vertex data
    277     glVertexAttribPointer( ATTRIB_VERTEX, 3, GL_FLOAT, GL_FALSE, iStride, BUFFER_OFFSET( 0 ) );
    278     glEnableVertexAttribArray( ATTRIB_VERTEX );
    279 
    280     glVertexAttribPointer( ATTRIB_NORMAL, 3, GL_FLOAT, GL_FALSE, iStride,
    281             BUFFER_OFFSET( 3 * sizeof(GLfloat) ) );
    282     glEnableVertexAttribArray( ATTRIB_NORMAL );
    283 
    284     // Bind the IB
    285     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ibo_ );
    286 
    287     glUseProgram( shader_param_.program_ );
    288 
    289     TEAPOT_MATERIALS material = { { 1.0f, 1.0f, 1.0f, 10.f }, { 0.1f, 0.1f, 0.1f }, };
    290 
    291     //Update uniforms
    292     //
    293     //using glUniform3fv here was troublesome..
    294     //
    295     glUniform4f( shader_param_.material_specular_, material.specular_color[0],
    296             material.specular_color[1], material.specular_color[2], material.specular_color[3] );
    297     glUniform3f( shader_param_.material_ambient_, material.ambient_color[0],
    298             material.ambient_color[1], material.ambient_color[2] );
    299 
    300     glUniform3f( shader_param_.light0_, 100.f, -200.f, -600.f );
    301 
    302     if( geometry_instancing_support_ )
    303     {
    304         //
    305         //Geometry instancing, new feature in GLES3.0
    306         //
    307 
    308         //Update UBO
    309         glBindBuffer( GL_UNIFORM_BUFFER, ubo_ );
    310         float* p = (float*) glMapBufferRange( GL_UNIFORM_BUFFER, 0,
    311                 teapot_x_ * teapot_y_ * teapot_z_ * (ubo_matrix_stride_ * 2) * sizeof(float),
    312                 GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_RANGE_BIT );
    313         float* pMVPMat = p;
    314         float* pMVMat = p + teapot_x_ * teapot_y_ * teapot_z_ * ubo_matrix_stride_;
    315         for( int32_t i = 0; i < teapot_x_ * teapot_y_ * teapot_z_; ++i )
    316         {
    317             //Rotation
    318             float fX, fY;
    319             vec_current_rotations_[i] += vec_rotations_[i];
    320             vec_current_rotations_[i].Value( fX, fY );
    321             ndk_helper::Mat4 mat_rotation = ndk_helper::Mat4::RotationX( fX )
    322                     * ndk_helper::Mat4::RotationY( fY );
    323 
    324             // Feed Projection and Model View matrices to the shaders
    325             ndk_helper::Mat4 mat_v = mat_view_ * vec_mat_models_[i] * mat_rotation;
    326             ndk_helper::Mat4 mat_vp = mat_projection_ * mat_v;
    327 
    328             memcpy( pMVPMat, mat_vp.Ptr(), sizeof(mat_v) );
    329             pMVPMat += ubo_matrix_stride_;
    330 
    331             memcpy( pMVMat, mat_v.Ptr(), sizeof(mat_v) );
    332             pMVMat += ubo_matrix_stride_;
    333         }
    334         glUnmapBuffer( GL_UNIFORM_BUFFER );
    335 
    336         //Instanced rendering
    337         glDrawElementsInstanced( GL_TRIANGLES, num_indices_, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0),
    338                 teapot_x_ * teapot_y_ * teapot_z_ );
    339 
    340     }
    341     else
    342     {
    343         //Regular rendering pass
    344         for( int32_t i = 0; i < teapot_x_ * teapot_y_ * teapot_z_; ++i )
    345         {
    346             //Set diffuse
    347             float x, y, z;
    348             vec_colors_[i].Value( x, y, z );
    349             glUniform4f( shader_param_.material_diffuse_, x, y, z, 1.f );
    350 
    351             //Rotation
    352             vec_current_rotations_[i] += vec_rotations_[i];
    353             vec_current_rotations_[i].Value( x, y );
    354             ndk_helper::Mat4 mat_rotation = ndk_helper::Mat4::RotationX( x )
    355                     * ndk_helper::Mat4::RotationY( y );
    356 
    357             // Feed Projection and Model View matrices to the shaders
    358             ndk_helper::Mat4 mat_v = mat_view_ * vec_mat_models_[i] * mat_rotation;
    359             ndk_helper::Mat4 mat_vp = mat_projection_ * mat_v;
    360             glUniformMatrix4fv( shader_param_.matrix_projection_, 1, GL_FALSE, mat_vp.Ptr() );
    361             glUniformMatrix4fv( shader_param_.matrix_view_, 1, GL_FALSE, mat_v.Ptr() );
    362 
    363             glDrawElements( GL_TRIANGLES, num_indices_, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0) );
    364 
    365         }
    366     }
    367 
    368     glBindBuffer( GL_ARRAY_BUFFER, 0 );
    369     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
    370 }
    371 
    372 //--------------------------------------------------------------------------------
    373 // LoadShaders
    374 //--------------------------------------------------------------------------------
    375 bool MoreTeapotsRenderer::LoadShaders( SHADER_PARAMS* params,
    376         const char* strVsh,
    377         const char* strFsh )
    378 {
    379     //
    380     //Shader load for GLES2
    381     //In GLES2.0, shader attribute locations need to be explicitly specified before linking
    382     //
    383     GLuint program;
    384     GLuint vertShader, fragShader;
    385     char *vertShaderPathname, *fragShaderPathname;
    386 
    387     // Create shader program
    388     program = glCreateProgram();
    389     LOGI( "Created Shader %d", program );
    390 
    391     // Create and compile vertex shader
    392     if( !ndk_helper::shader::CompileShader( &vertShader, GL_VERTEX_SHADER, strVsh ) )
    393     {
    394         LOGI( "Failed to compile vertex shader" );
    395         glDeleteProgram( program );
    396         return false;
    397     }
    398 
    399     // Create and compile fragment shader
    400     if( !ndk_helper::shader::CompileShader( &fragShader, GL_FRAGMENT_SHADER, strFsh ) )
    401     {
    402         LOGI( "Failed to compile fragment shader" );
    403         glDeleteProgram( program );
    404         return false;
    405     }
    406 
    407     // Attach vertex shader to program
    408     glAttachShader( program, vertShader );
    409 
    410     // Attach fragment shader to program
    411     glAttachShader( program, fragShader );
    412 
    413     // Bind attribute locations
    414     // this needs to be done prior to linking
    415     glBindAttribLocation( program, ATTRIB_VERTEX, "myVertex" );
    416     glBindAttribLocation( program, ATTRIB_NORMAL, "myNormal" );
    417 
    418     // Link program
    419     if( !ndk_helper::shader::LinkProgram( program ) )
    420     {
    421         LOGI( "Failed to link program: %d", program );
    422 
    423         if( vertShader )
    424         {
    425             glDeleteShader( vertShader );
    426             vertShader = 0;
    427         }
    428         if( fragShader )
    429         {
    430             glDeleteShader( fragShader );
    431             fragShader = 0;
    432         }
    433         if( program )
    434         {
    435             glDeleteProgram( program );
    436         }
    437         return false;
    438     }
    439 
    440     // Get uniform locations
    441     params->matrix_projection_ = glGetUniformLocation( program, "uPMatrix" );
    442     params->matrix_view_ = glGetUniformLocation( program, "uMVMatrix" );
    443 
    444     params->light0_ = glGetUniformLocation( program, "vLight0" );
    445     params->material_diffuse_ = glGetUniformLocation( program, "vMaterialDiffuse" );
    446     params->material_ambient_ = glGetUniformLocation( program, "vMaterialAmbient" );
    447     params->material_specular_ = glGetUniformLocation( program, "vMaterialSpecular" );
    448 
    449     // Release vertex and fragment shaders
    450     if( vertShader )
    451         glDeleteShader( vertShader );
    452     if( fragShader )
    453         glDeleteShader( fragShader );
    454 
    455     params->program_ = program;
    456     return true;
    457 }
    458 
    459 bool MoreTeapotsRenderer::LoadShadersES3( SHADER_PARAMS* params,
    460         const char* strVsh,
    461         const char* strFsh,
    462         std::map<std::string, std::string>&shaderParams )
    463 {
    464     //
    465     //Shader load for GLES3
    466     //In GLES3.0, shader attribute index can be described in a shader code directly with layout() attribute
    467     //
    468     GLuint program;
    469     GLuint vertShader, fragShader;
    470     char *vertShaderPathname, *fragShaderPathname;
    471 
    472     // Create shader program
    473     program = glCreateProgram();
    474     LOGI( "Created Shader %d", program );
    475 
    476     // Create and compile vertex shader
    477     if( !ndk_helper::shader::CompileShader( &vertShader, GL_VERTEX_SHADER, strVsh, shaderParams ) )
    478     {
    479         LOGI( "Failed to compile vertex shader" );
    480         glDeleteProgram( program );
    481         return false;
    482     }
    483 
    484     // Create and compile fragment shader
    485     if( !ndk_helper::shader::CompileShader( &fragShader, GL_FRAGMENT_SHADER, strFsh,
    486             shaderParams ) )
    487     {
    488         LOGI( "Failed to compile fragment shader" );
    489         glDeleteProgram( program );
    490         return false;
    491     }
    492 
    493     // Attach vertex shader to program
    494     glAttachShader( program, vertShader );
    495 
    496     // Attach fragment shader to program
    497     glAttachShader( program, fragShader );
    498 
    499     // Link program
    500     if( !ndk_helper::shader::LinkProgram( program ) )
    501     {
    502         LOGI( "Failed to link program: %d", program );
    503 
    504         if( vertShader )
    505         {
    506             glDeleteShader( vertShader );
    507             vertShader = 0;
    508         }
    509         if( fragShader )
    510         {
    511             glDeleteShader( fragShader );
    512             fragShader = 0;
    513         }
    514         if( program )
    515         {
    516             glDeleteProgram( program );
    517         }
    518 
    519         return false;
    520     }
    521 
    522     // Get uniform locations
    523     params->light0_ = glGetUniformLocation( program, "vLight0" );
    524     params->material_ambient_ = glGetUniformLocation( program, "vMaterialAmbient" );
    525     params->material_specular_ = glGetUniformLocation( program, "vMaterialSpecular" );
    526 
    527     // Release vertex and fragment shaders
    528     if( vertShader )
    529         glDeleteShader( vertShader );
    530     if( fragShader )
    531         glDeleteShader( fragShader );
    532 
    533     params->program_ = program;
    534     return true;
    535 }
    536 
    537 //--------------------------------------------------------------------------------
    538 // Bind
    539 //--------------------------------------------------------------------------------
    540 bool MoreTeapotsRenderer::Bind( ndk_helper::TapCamera* camera )
    541 {
    542     camera_ = camera;
    543     return true;
    544 }
    545 
    546 //--------------------------------------------------------------------------------
    547 // Helper functions
    548 //--------------------------------------------------------------------------------
    549 std::string MoreTeapotsRenderer::ToString( const int32_t i )
    550 {
    551     char str[64];
    552     snprintf( str, sizeof(str), "%d", i );
    553     return std::string( str );
    554 }
    555 
    556