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