/* Copyright (c) 2012, Broadcom Europe Ltd Copyright (c) 2012, OtherCrashOverride All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces. #include #include #include #include #include #include #include #include #include #include "cube_texture_and_coords.h" #include "models.h" #include "teapot.h" #include "RaspiTex.h" #include "RaspiTexUtil.h" #define PATH "./" #ifndef M_PI #define M_PI 3.141592654 #endif typedef struct { uint32_t screen_width; uint32_t screen_height; GLuint tex; // model rotation vector and direction GLfloat rot_angle_x_inc; GLfloat rot_angle_y_inc; GLfloat rot_angle_z_inc; // current model rotation angles GLfloat rot_angle_x; GLfloat rot_angle_y; GLfloat rot_angle_z; // current distance from camera GLfloat distance; GLfloat distance_inc; MODEL_T model; } TEAPOT_STATE_T; static void init_ogl(TEAPOT_STATE_T *state); static void init_model_proj(TEAPOT_STATE_T *state); static void reset_model(TEAPOT_STATE_T *state); static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc); static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc); /*********************************************************** * Name: init_ogl * * Arguments: * TEAPOT_STATE_T *state - holds OGLES model info * * Description: Sets the display, OpenGL|ES context and screen stuff * * Returns: void * ***********************************************************/ static void init_ogl(TEAPOT_STATE_T *state) { // Set background color and clear buffers glClearColor((0.3922f+7*0.5f)/8, (0.1176f+7*0.5f)/8, (0.5882f+7*0.5f)/8, 1.0f); // Enable back face culling. glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); glClearDepthf(1.0); glDepthFunc(GL_LEQUAL); float noAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_AMBIENT, noAmbient); glEnable(GL_LIGHT0); glEnable(GL_LIGHTING); } /*********************************************************** * Name: init_model_proj * * Arguments: * TEAPOT_STATE_T *state - holds OGLES model info * * Description: Sets the OpenGL|ES model to default values * * Returns: void * ***********************************************************/ static void init_model_proj(TEAPOT_STATE_T *state) { float nearp = 0.1f; float farp = 500.0f; float hht; float hwd; glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI); hwd = hht * (float)state->screen_width / (float)state->screen_height; glFrustumf(-hwd, hwd, -hht, hht, nearp, farp); glEnableClientState( GL_VERTEX_ARRAY ); reset_model(state); } /*********************************************************** * Name: reset_model * * Arguments: * TEAPOT_STATE_T *state - holds OGLES model info * * Description: Resets the Model projection and rotation direction * * Returns: void * ***********************************************************/ static void reset_model(TEAPOT_STATE_T *state) { // reset model position glMatrixMode(GL_MODELVIEW); // reset model rotation state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f; state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f; state->distance = 0.8f*1.5f; } /*********************************************************** * Name: teapot_update_model * * Arguments: * TEAPOT_STATE_T *state - holds OGLES model info * * Description: Updates model projection to current position/rotation * * Returns: void * ***********************************************************/ static int teapot_update_model(RASPITEX_STATE *raspitex_state) { TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state; // update position state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc); state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc); state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc); state->distance = inc_and_clip_distance(state->distance, state->distance_inc); glLoadIdentity(); // move camera back to see the cube glTranslatef(0.f, 0.f, -state->distance); // Rotate model to new position glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f); glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f); glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f); return 0; } /*********************************************************** * Name: inc_and_wrap_angle * * Arguments: * GLfloat angle current angle * GLfloat angle_inc angle increment * * Description: Increments or decrements angle by angle_inc degrees * Wraps to 0 at 360 deg. * * Returns: new value of angle * ***********************************************************/ static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc) { angle += angle_inc; if (angle >= 360.0) angle -= 360.f; else if (angle <=0) angle += 360.f; return angle; } /*********************************************************** * Name: inc_and_clip_distance * * Arguments: * GLfloat distance current distance * GLfloat distance_inc distance increment * * Description: Increments or decrements distance by distance_inc units * Clips to range * * Returns: new value of angle * ***********************************************************/ static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc) { distance += distance_inc; if (distance >= 10.0f) distance = 10.f; else if (distance <= 1.0f) distance = 1.0f; return distance; } /*********************************************************** * Name: teapot_redraw * * Arguments: * RASPITEX_STATE_T *state - holds OGLES model info * * Description: Draws the model * * Returns: void * ***********************************************************/ static int teapot_redraw(RASPITEX_STATE *raspitex_state) { TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state; // Start with a clear screen glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* Bind the OES texture which is used to render the camera preview */ glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture); draw_wavefront(state->model, raspitex_state->texture); return 0; } //============================================================================== static int teapot_gl_init(RASPITEX_STATE *raspitex_state) { const char *model_path = "/opt/vc/src/hello_pi/hello_teapot/teapot.obj.dat"; TEAPOT_STATE_T *state = NULL; int rc = 0; // Clear scene state state = calloc(1, sizeof(TEAPOT_STATE_T)); raspitex_state->scene_state = state; state->screen_width = raspitex_state->width; state->screen_height = raspitex_state->height; rc = raspitexutil_gl_init_1_0(raspitex_state); if (rc != 0) goto end; // Start OGLES init_ogl(state); // Setup the model world init_model_proj(state); state->model = load_wavefront(model_path, NULL); if (! state->model) { vcos_log_error("Failed to load model from %s\n", model_path); rc = -1; } end: return rc; } static void teapot_gl_term(RASPITEX_STATE *raspitex_state) { vcos_log_trace("%s:", VCOS_FUNCTION); TEAPOT_STATE_T *state = raspitex_state->scene_state; if (state) { if (state->model) unload_wavefront(state->model); raspitexutil_gl_term(raspitex_state); free(raspitex_state->scene_state); raspitex_state->scene_state = NULL; } } int teapot_open(RASPITEX_STATE *raspitex_state) { raspitex_state->ops.gl_init = teapot_gl_init; raspitex_state->ops.update_model = teapot_update_model; raspitex_state->ops.redraw = teapot_redraw; raspitex_state->ops.gl_term = teapot_gl_term; raspitex_state->ops.update_texture = raspitexutil_update_texture; return 0; }