1/*
2Copyright (c) 2012, Broadcom Europe Ltd
3Copyright (c) 2012, OtherCrashOverride
4All rights reserved.
5
6Redistribution and use in source and binary forms, with or without
7modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of the copyright holder nor the
14 names of its contributors may be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
21DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27*/
28
29// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces.
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <string.h>
34#include <math.h>
35#include <assert.h>
36#include <unistd.h>
37
38#include <GLES/gl.h>
39#include <EGL/egl.h>
40#include <EGL/eglext.h>
41
42#include "cube_texture_and_coords.h"
43#include "models.h"
44#include "teapot.h"
45
46#include "RaspiTex.h"
47#include "RaspiTexUtil.h"
48
49#define PATH "./"
50
51#ifndef M_PI
52 #define M_PI 3.141592654
53#endif
54
55typedef struct
56{
57 uint32_t screen_width;
58 uint32_t screen_height;
59 GLuint tex;
60// model rotation vector and direction
61 GLfloat rot_angle_x_inc;
62 GLfloat rot_angle_y_inc;
63 GLfloat rot_angle_z_inc;
64// current model rotation angles
65 GLfloat rot_angle_x;
66 GLfloat rot_angle_y;
67 GLfloat rot_angle_z;
68// current distance from camera
69 GLfloat distance;
70 GLfloat distance_inc;
71 MODEL_T model;
72} TEAPOT_STATE_T;
73
74static void init_ogl(TEAPOT_STATE_T *state);
75static void init_model_proj(TEAPOT_STATE_T *state);
76static void reset_model(TEAPOT_STATE_T *state);
77static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc);
78static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc);
79
80/***********************************************************
81 * Name: init_ogl
82 *
83 * Arguments:
84 * TEAPOT_STATE_T *state - holds OGLES model info
85 *
86 * Description: Sets the display, OpenGL|ES context and screen stuff
87 *
88 * Returns: void
89 *
90 ***********************************************************/
91static void init_ogl(TEAPOT_STATE_T *state)
92{
93 // Set background color and clear buffers
94 glClearColor((0.3922f+7*0.5f)/8, (0.1176f+7*0.5f)/8, (0.5882f+7*0.5f)/8, 1.0f);
95
96 // Enable back face culling.
97 glEnable(GL_CULL_FACE);
98
99 glEnable(GL_DEPTH_TEST);
100 glClearDepthf(1.0);
101 glDepthFunc(GL_LEQUAL);
102
103 float noAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
104 glLightfv(GL_LIGHT0, GL_AMBIENT, noAmbient);
105 glEnable(GL_LIGHT0);
106 glEnable(GL_LIGHTING);
107}
108
109/***********************************************************
110 * Name: init_model_proj
111 *
112 * Arguments:
113 * TEAPOT_STATE_T *state - holds OGLES model info
114 *
115 * Description: Sets the OpenGL|ES model to default values
116 *
117 * Returns: void
118 *
119 ***********************************************************/
120static void init_model_proj(TEAPOT_STATE_T *state)
121{
122 float nearp = 0.1f;
123 float farp = 500.0f;
124 float hht;
125 float hwd;
126
127 glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
128
129 glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height);
130
131 glMatrixMode(GL_PROJECTION);
132 glLoadIdentity();
133
134 hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI);
135 hwd = hht * (float)state->screen_width / (float)state->screen_height;
136
137 glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);
138
139 glEnableClientState( GL_VERTEX_ARRAY );
140
141 reset_model(state);
142}
143
144/***********************************************************
145 * Name: reset_model
146 *
147 * Arguments:
148 * TEAPOT_STATE_T *state - holds OGLES model info
149 *
150 * Description: Resets the Model projection and rotation direction
151 *
152 * Returns: void
153 *
154 ***********************************************************/
155static void reset_model(TEAPOT_STATE_T *state)
156{
157 // reset model position
158 glMatrixMode(GL_MODELVIEW);
159
160 // reset model rotation
161 state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f;
162 state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f;
163 state->distance = 0.8f*1.5f;
164}
165
166/***********************************************************
167 * Name: teapot_update_model
168 *
169 * Arguments:
170 * TEAPOT_STATE_T *state - holds OGLES model info
171 *
172 * Description: Updates model projection to current position/rotation
173 *
174 * Returns: void
175 *
176 ***********************************************************/
177static int teapot_update_model(RASPITEX_STATE *raspitex_state)
178{
179 TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state;
180
181 // update position
182 state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc);
183 state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc);
184 state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc);
185 state->distance = inc_and_clip_distance(state->distance, state->distance_inc);
186
187 glLoadIdentity();
188 // move camera back to see the cube
189 glTranslatef(0.f, 0.f, -state->distance);
190
191 // Rotate model to new position
192 glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f);
193 glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f);
194 glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f);
195
196 return 0;
197}
198
199/***********************************************************
200 * Name: inc_and_wrap_angle
201 *
202 * Arguments:
203 * GLfloat angle current angle
204 * GLfloat angle_inc angle increment
205 *
206 * Description: Increments or decrements angle by angle_inc degrees
207 * Wraps to 0 at 360 deg.
208 *
209 * Returns: new value of angle
210 *
211 ***********************************************************/
212static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc)
213{
214 angle += angle_inc;
215
216 if (angle >= 360.0)
217 angle -= 360.f;
218 else if (angle <=0)
219 angle += 360.f;
220
221 return angle;
222}
223
224/***********************************************************
225 * Name: inc_and_clip_distance
226 *
227 * Arguments:
228 * GLfloat distance current distance
229 * GLfloat distance_inc distance increment
230 *
231 * Description: Increments or decrements distance by distance_inc units
232 * Clips to range
233 *
234 * Returns: new value of angle
235 *
236 ***********************************************************/
237static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc)
238{
239 distance += distance_inc;
240
241 if (distance >= 10.0f)
242 distance = 10.f;
243 else if (distance <= 1.0f)
244 distance = 1.0f;
245
246 return distance;
247}
248
249/***********************************************************
250 * Name: teapot_redraw
251 *
252 * Arguments:
253 * RASPITEX_STATE_T *state - holds OGLES model info
254 *
255 * Description: Draws the model
256 *
257 * Returns: void
258 *
259 ***********************************************************/
260static int teapot_redraw(RASPITEX_STATE *raspitex_state)
261{
262 TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state;
263
264 // Start with a clear screen
265 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
266
267 /* Bind the OES texture which is used to render the camera preview */
268 glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture);
269 draw_wavefront(state->model, raspitex_state->texture);
270 return 0;
271}
272
273//==============================================================================
274
275static int teapot_gl_init(RASPITEX_STATE *raspitex_state)
276{
277 const char *model_path = "/opt/vc/src/hello_pi/hello_teapot/teapot.obj.dat";
278 TEAPOT_STATE_T *state = NULL;
279 int rc = 0;
280
281 // Clear scene state
282 state = calloc(1, sizeof(TEAPOT_STATE_T));
283 raspitex_state->scene_state = state;
284 state->screen_width = raspitex_state->width;
285 state->screen_height = raspitex_state->height;
286
287 rc = raspitexutil_gl_init_1_0(raspitex_state);
288 if (rc != 0)
289 goto end;
290
291 // Start OGLES
292 init_ogl(state);
293
294 // Setup the model world
295 init_model_proj(state);
296 state->model = load_wavefront(model_path, NULL);
297
298 if (! state->model)
299 {
300 vcos_log_error("Failed to load model from %s\n", model_path);
301 rc = -1;
302 }
303
304end:
305 return rc;
306}
307
308static void teapot_gl_term(RASPITEX_STATE *raspitex_state)
309{
310 vcos_log_trace("%s:", VCOS_FUNCTION);
311
312 TEAPOT_STATE_T *state = raspitex_state->scene_state;
313 if (state)
314 {
315 if (state->model)
316 unload_wavefront(state->model);
317 raspitexutil_gl_term(raspitex_state);
318 free(raspitex_state->scene_state);
319 raspitex_state->scene_state = NULL;
320 }
321}
322
323int teapot_open(RASPITEX_STATE *raspitex_state)
324{
325 raspitex_state->ops.gl_init = teapot_gl_init;
326 raspitex_state->ops.update_model = teapot_update_model;
327 raspitex_state->ops.redraw = teapot_redraw;
328 raspitex_state->ops.gl_term = teapot_gl_term;
329 raspitex_state->ops.update_texture = raspitexutil_update_texture;
330 return 0;
331}
332
333