Also, that is making a lot of 2-triangle draw calls. You really want to batch as many triangles as you can in each draw call and you want to make the minimum number of state changes between each draw call. Every time you have to send a command to the GPU there is an overhead, and the overheads for changing texture, matrix transformation and a draw call every 2 triangles is going to add up to a huge amount of time.
I made a few quick modifications,
- Turned on the Z-buffer (otherwise things further away can end up drawn on top of things near).
- Changed the texture usage to load the three images onto separate quadrants of one texture.
- Modified the texture coordinates of the cube's faces so that each face uses the relevant quadrant.
- Made the draw call draw all the cube in one go.
I didn't map the rotations of each face, should be a case of modifying the vertices and/or texture coords to match what was desired.
Nor did I re-order the triangle strips to make the faces follow on properly, as the cube is defined front face then back face, it will draw triangles joining those two faces which aren't wanted. The Z buffering should hide most of it but it really needs the vertices re-ordering so that each triangle follows on from the previous rather than jumping around, but this was a quick hack.
Modified
triangle.c to draw each cube in one go, just the functions I changed are listed (don't think I missed anything)
Code: Select all
// Added requesting and enabling the depth buffer
static void init_ogl(CUBE_STATE_T *state)
{
int32_t success = 0;
EGLBoolean result;
EGLint num_config;
static EGL_DISPMANX_WINDOW_T nativewindow;
DISPMANX_UPDATE_HANDLE_T dispman_update;
VC_RECT_T dst_rect;
VC_RECT_T src_rect;
static const EGLint attribute_list[] =
{
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_ALPHA_SIZE, 8,
EGL_DEPTH_SIZE, 16,
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
EGL_NONE
};
EGLConfig config;
// get an EGL display connection
state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
assert(state->display!=EGL_NO_DISPLAY);
// initialize the EGL display connection
result = eglInitialize(state->display, NULL, NULL);
assert(EGL_FALSE != result);
// get an appropriate EGL frame buffer configuration
result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
assert(EGL_FALSE != result);
// create an EGL rendering context
state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
assert(state->context!=EGL_NO_CONTEXT);
// create an EGL window surface
success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
assert( success >= 0 );
dst_rect.x = 0;
dst_rect.y = 0;
dst_rect.width = state->screen_width;
dst_rect.height = state->screen_height;
src_rect.x = 0;
src_rect.y = 0;
src_rect.width = state->screen_width << 16;
src_rect.height = state->screen_height << 16;
state->dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
dispman_update = vc_dispmanx_update_start( 0 );
state->dispman_element = vc_dispmanx_element_add ( dispman_update, state->dispman_display,
0/*layer*/, &dst_rect, 0/*src*/,
&src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
nativewindow.element = state->dispman_element;
nativewindow.width = state->screen_width;
nativewindow.height = state->screen_height;
vc_dispmanx_update_submit_sync( dispman_update );
state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
assert(state->surface != EGL_NO_SURFACE);
// connect the context to the surface
result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
assert(EGL_FALSE != result);
// Set background color and clear buffers
glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
// Enable back face culling.
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_MODELVIEW);
}
// Draw all triangles of a cube in one go
static void redraw_scene(CUBE_STATE_T *state)
{
// Start with a clear screen (and depth buffer)
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// Draw all faces:
// Bind texture surface to current vertices
glBindTexture(GL_TEXTURE_2D, state->tex[0]);
// Need to rotate textures - do this by rotating each cube face
glRotatef(270.f, 0.f, 0.f, 1.f ); // front face normal along z axis
int x, y;
for( y = 0; y < 20; y++)
{
glPushMatrix();
glTranslatef( (y-10)*10, 0, 0 );
for( x = 0; x < 20; x++)
{
glPushMatrix();
glTranslatef( 0, (x-10)*10, 0 );
glScalef( 0.1f, 0.1f, 0.1f );
// draw all 24 vertices in one go
glDrawArrays( GL_TRIANGLE_STRIP, 0, 24);
//***** ok, the rotates haven't been done but that should really be fixed in the model
// same pattern for other 5 faces - rotation chosen to make image orientation 'nice'
//glBindTexture(GL_TEXTURE_2D, state->tex[1]);
//glRotatef(90.f, 0.f, 0.f, 1.f ); // back face normal along z axis
//glDrawArrays( GL_TRIANGLE_STRIP, 4, 4);
//glBindTexture(GL_TEXTURE_2D, state->tex[2]);
//glRotatef(90.f, 1.f, 0.f, 0.f ); // left face normal along x axis
//glDrawArrays( GL_TRIANGLE_STRIP, 8, 4);
//glBindTexture(GL_TEXTURE_2D, state->tex[3]);
//glRotatef(90.f, 1.f, 0.f, 0.f ); // right face normal along x axis
//glDrawArrays( GL_TRIANGLE_STRIP, 12, 4);
//glBindTexture(GL_TEXTURE_2D, state->tex[4]);
//glRotatef(270.f, 0.f, 1.f, 0.f ); // top face normal along y axis
//glDrawArrays( GL_TRIANGLE_STRIP, 16, 4);
//glBindTexture(GL_TEXTURE_2D, state->tex[5]);
//glRotatef(90.f, 0.f, 1.f, 0.f ); // bottom face normal along y axis
//glDrawArrays( GL_TRIANGLE_STRIP, 20, 4);
glPopMatrix();
}
glPopMatrix();
}
eglSwapBuffers(state->display, state->surface);
}
// Put all three images onto one texture so you don't need to keep binding
static void init_textures(CUBE_STATE_T *state)
{
// load three texture buffers but use them on quadrants of one OGL|ES texture surface
load_tex_images(state);
glGenTextures(1, &state->tex[0]);
// setup texture
glBindTexture(GL_TEXTURE_2D, state->tex[0]);
// Create the texture at twice the resolution of one image so we can
// put each image into it's own quadrant of the texture.
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 2*IMAGE_SIZE, 2*IMAGE_SIZE, 0,
GL_RGB, GL_UNSIGNED_BYTE, NULL);
// image 1 (old tex[0] and tex[1]) is lower left (0.0, 0.0) -> (0.5, 0.5)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, IMAGE_SIZE, IMAGE_SIZE,
GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf1);
// image 2 (old tex[2] and tex[3] is lower right (0.5, 0.0) -> (1.0, 0.5)
glTexSubImage2D(GL_TEXTURE_2D, 0, IMAGE_SIZE, 0, IMAGE_SIZE, IMAGE_SIZE,
GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf2);
// image 3 (old tex[4] and tex[5] is upper left (0.0, 0.5) -> (0.5, 1.0)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, IMAGE_SIZE, IMAGE_SIZE, IMAGE_SIZE,
GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf3);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
// setup overall texture environment
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
}
The modified texture coordinates in
cube_texture_and_coords.h
Code: Select all
/** Texture coordinates for the quad. */
static const GLfloat texCoords[6 * 4 * 2] = {
0.0f, 0.0f,
0.0f, 0.5f,
0.5f, 0.0f,
0.5f, 0.5f,
0.0f, 0.0f,
0.0f, 0.5f,
0.5f, 0.0f,
0.5f, 0.5f,
0.5f, 0.0f,
0.5f, 0.5f,
1.0f, 0.0f,
1.0f, 0.5f,
0.5f, 0.0f,
0.5f, 0.5f,
1.0f, 0.0f,
1.0f, 0.5f,
0.0f, 0.5f,
0.0f, 1.0f,
0.5f, 0.5f,
0.5f, 1.0f,
0.0f, 0.5f,
0.0f, 1.0f,
0.5f, 0.5f,
0.5f, 1.0f
};