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 //--------------------------------------------------------------------------------
MoreTeapotsRenderer()34 MoreTeapotsRenderer::MoreTeapotsRenderer() :
35 geometry_instancing_support_( false )
36 {
37
38 }
39
40 //--------------------------------------------------------------------------------
41 // Dtor
42 //--------------------------------------------------------------------------------
~MoreTeapotsRenderer()43 MoreTeapotsRenderer::~MoreTeapotsRenderer()
44 {
45 Unload();
46 }
47
48 //--------------------------------------------------------------------------------
49 // Init
50 //--------------------------------------------------------------------------------
Init(const int32_t numX,const int32_t numY,const int32_t numZ)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
UpdateViewport()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 //--------------------------------------------------------------------------------
Unload()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 //--------------------------------------------------------------------------------
Update(float fTime)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 //--------------------------------------------------------------------------------
Render()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 //--------------------------------------------------------------------------------
LoadShaders(SHADER_PARAMS * params,const char * strVsh,const char * strFsh)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
LoadShadersES3(SHADER_PARAMS * params,const char * strVsh,const char * strFsh,std::map<std::string,std::string> & shaderParams)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 //--------------------------------------------------------------------------------
Bind(ndk_helper::TapCamera * camera)540 bool MoreTeapotsRenderer::Bind( ndk_helper::TapCamera* camera )
541 {
542 camera_ = camera;
543 return true;
544 }
545
546 //--------------------------------------------------------------------------------
547 // Helper functions
548 //--------------------------------------------------------------------------------
ToString(const int32_t i)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