1/* 2 * Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> 3 * 4 * Based on eglgears by 5 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 */ 24 25#include <stdlib.h> 26#include <stdio.h> 27#include <math.h> 28#include <assert.h> 29 30#include <GLES/gl.h> 31#include "eglut.h" 32 33#ifndef M_PI 34#define M_PI 3.14159265 35#endif 36 37 38struct gear { 39 GLuint vbo; 40 GLfloat *vertices; 41 GLsizei stride; 42 43 GLint num_teeth; 44}; 45 46static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; 47static struct gear gears[3]; 48static GLfloat angle = 0.0; 49 50/* 51 * Initialize a gear wheel. 52 * 53 * Input: gear - gear to initialize 54 * inner_radius - radius of hole at center 55 * outer_radius - radius at center of teeth 56 * width - width of gear 57 * teeth - number of teeth 58 * tooth_depth - depth of tooth 59 */ 60static void 61init_gear(struct gear *gear, GLfloat inner_radius, GLfloat outer_radius, 62 GLfloat width, GLint teeth, GLfloat tooth_depth) 63{ 64 GLfloat r0, r1, r2; 65 GLfloat a0, da; 66 GLint verts_per_tooth, total_verts, total_size; 67 GLint count, i; 68 GLfloat *verts; 69 70 r0 = inner_radius; 71 r1 = outer_radius - tooth_depth / 2.0; 72 r2 = outer_radius + tooth_depth / 2.0; 73 74 a0 = 2.0 * M_PI / teeth; 75 da = a0 / 4.0; 76 77 gear->vbo = 0; 78 gear->vertices = NULL; 79 gear->stride = sizeof(GLfloat) * 6; /* XYZ + normal */ 80 gear->num_teeth = teeth; 81 82 verts_per_tooth = 10 + 4; 83 total_verts = teeth * verts_per_tooth; 84 total_size = total_verts * gear->stride; 85 86 verts = malloc(total_size); 87 if (!verts) { 88 printf("failed to allocate vertices\n"); 89 return; 90 } 91 92#define GEAR_VERT(r, n, sign) \ 93 do { \ 94 verts[count * 6 + 0] = (r) * vx[n]; \ 95 verts[count * 6 + 1] = (r) * vy[n]; \ 96 verts[count * 6 + 2] = (sign) * width * 0.5; \ 97 verts[count * 6 + 3] = normal[0]; \ 98 verts[count * 6 + 4] = normal[1]; \ 99 verts[count * 6 + 5] = normal[2]; \ 100 count++; \ 101 } while (0) 102 103 count = 0; 104 for (i = 0; i < teeth; i++) { 105 GLfloat normal[3]; 106 GLfloat vx[5], vy[5]; 107 GLfloat u, v; 108 109 normal[0] = 0.0; 110 normal[1] = 0.0; 111 normal[2] = 0.0; 112 113 vx[0] = cos(i * a0 + 0 * da); 114 vy[0] = sin(i * a0 + 0 * da); 115 vx[1] = cos(i * a0 + 1 * da); 116 vy[1] = sin(i * a0 + 1 * da); 117 vx[2] = cos(i * a0 + 2 * da); 118 vy[2] = sin(i * a0 + 2 * da); 119 vx[3] = cos(i * a0 + 3 * da); 120 vy[3] = sin(i * a0 + 3 * da); 121 vx[4] = cos(i * a0 + 4 * da); 122 vy[4] = sin(i * a0 + 4 * da); 123 124 /* outward faces of a tooth, 10 verts */ 125 normal[0] = vx[0]; 126 normal[1] = vy[0]; 127 GEAR_VERT(r1, 0, 1); 128 GEAR_VERT(r1, 0, -1); 129 130 u = r2 * vx[1] - r1 * vx[0]; 131 v = r2 * vy[1] - r1 * vy[0]; 132 normal[0] = v; 133 normal[1] = -u; 134 GEAR_VERT(r2, 1, 1); 135 GEAR_VERT(r2, 1, -1); 136 137 normal[0] = vx[0]; 138 normal[1] = vy[0]; 139 GEAR_VERT(r2, 2, 1); 140 GEAR_VERT(r2, 2, -1); 141 142 u = r1 * vx[3] - r2 * vx[2]; 143 v = r1 * vy[3] - r2 * vy[2]; 144 normal[0] = v; 145 normal[1] = -u; 146 GEAR_VERT(r1, 3, 1); 147 GEAR_VERT(r1, 3, -1); 148 149 normal[0] = vx[0]; 150 normal[1] = vy[0]; 151 GEAR_VERT(r1, 4, 1); 152 GEAR_VERT(r1, 4, -1); 153 154 /* inside radius cylinder, 4 verts */ 155 normal[0] = -vx[4]; 156 normal[1] = -vy[4]; 157 GEAR_VERT(r0, 4, 1); 158 GEAR_VERT(r0, 4, -1); 159 160 normal[0] = -vx[0]; 161 normal[1] = -vy[0]; 162 GEAR_VERT(r0, 0, 1); 163 GEAR_VERT(r0, 0, -1); 164 165 assert(count % verts_per_tooth == 0); 166 } 167 assert(count == total_verts); 168#undef GEAR_VERT 169 170 gear->vertices = verts; 171 172 /* setup VBO */ 173 glGenBuffers(1, &gear->vbo); 174 if (gear->vbo) { 175 glBindBuffer(GL_ARRAY_BUFFER, gear->vbo); 176 glBufferData(GL_ARRAY_BUFFER, total_size, verts, GL_STATIC_DRAW); 177 } 178} 179 180 181static void 182draw_gear(const struct gear *gear) 183{ 184 GLint i; 185 186 if (!gear->vbo && !gear->vertices) { 187 printf("nothing to be drawn\n"); 188 return; 189 } 190 191 if (gear->vbo) { 192 glBindBuffer(GL_ARRAY_BUFFER, gear->vbo); 193 glVertexPointer(3, GL_FLOAT, gear->stride, (const GLvoid *) 0); 194 glNormalPointer(GL_FLOAT, gear->stride, (const GLvoid *) (sizeof(GLfloat) * 3)); 195 } else { 196 glBindBuffer(GL_ARRAY_BUFFER, 0); 197 glVertexPointer(3, GL_FLOAT, gear->stride, gear->vertices); 198 glNormalPointer(GL_FLOAT, gear->stride, gear->vertices + 3); 199 } 200 201 glEnableClientState(GL_VERTEX_ARRAY); 202 203 for (i = 0; i < gear->num_teeth; i++) { 204 const GLint base = (10 + 4) * i; 205 GLushort indices[7]; 206 207 glShadeModel(GL_FLAT); 208 209 /* front face */ 210 indices[0] = base + 12; 211 indices[1] = base + 0; 212 indices[2] = base + 2; 213 indices[3] = base + 4; 214 indices[4] = base + 6; 215 indices[5] = base + 8; 216 indices[6] = base + 10; 217 218 glNormal3f(0.0, 0.0, 1.0); 219 glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices); 220 221 /* back face */ 222 indices[0] = base + 13; 223 indices[1] = base + 11; 224 indices[2] = base + 9; 225 indices[3] = base + 7; 226 indices[4] = base + 5; 227 indices[5] = base + 3; 228 indices[6] = base + 1; 229 230 glNormal3f(0.0, 0.0, -1.0); 231 glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices); 232 233 glEnableClientState(GL_NORMAL_ARRAY); 234 235 /* outward face of a tooth */ 236 glDrawArrays(GL_TRIANGLE_STRIP, base, 10); 237 238 /* inside radius cylinder */ 239 glShadeModel(GL_SMOOTH); 240 glDrawArrays(GL_TRIANGLE_STRIP, base + 10, 4); 241 242 glDisableClientState(GL_NORMAL_ARRAY); 243 } 244 245 glDisableClientState(GL_VERTEX_ARRAY); 246} 247 248 249static void 250gears_draw(void) 251{ 252 static const GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; 253 static const GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; 254 static const GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; 255 256 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 257 258 glPushMatrix(); 259 glRotatef(view_rotx, 1.0, 0.0, 0.0); 260 glRotatef(view_roty, 0.0, 1.0, 0.0); 261 glRotatef(view_rotz, 0.0, 0.0, 1.0); 262 263 glPushMatrix(); 264 glTranslatef(-3.0, -2.0, 0.0); 265 glRotatef(angle, 0.0, 0.0, 1.0); 266 267 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); 268 draw_gear(&gears[0]); 269 270 glPopMatrix(); 271 272 glPushMatrix(); 273 glTranslatef(3.1, -2.0, 0.0); 274 glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); 275 276 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green); 277 draw_gear(&gears[1]); 278 279 glPopMatrix(); 280 281 glPushMatrix(); 282 glTranslatef(-3.1, 4.2, 0.0); 283 glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); 284 285 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); 286 draw_gear(&gears[2]); 287 288 glPopMatrix(); 289 290 glPopMatrix(); 291} 292 293 294static void gears_fini(void) 295{ 296 GLint i; 297 for (i = 0; i < 3; i++) { 298 struct gear *gear = &gears[i]; 299 if (gear->vbo) { 300 glDeleteBuffers(1, &gear->vbo); 301 gear->vbo = 0; 302 } 303 if (gear->vertices) { 304 free(gear->vertices); 305 gear->vertices = NULL; 306 } 307 } 308} 309 310 311static void gears_init(void) 312{ 313 static const GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; 314 315 glLightfv(GL_LIGHT0, GL_POSITION, pos); 316 glEnable(GL_CULL_FACE); 317 glEnable(GL_LIGHTING); 318 glEnable(GL_LIGHT0); 319 glEnable(GL_DEPTH_TEST); 320 glEnable(GL_NORMALIZE); 321 322 init_gear(&gears[0], 1.0, 4.0, 1.0, 20, 0.7); 323 init_gear(&gears[1], 0.5, 2.0, 2.0, 10, 0.7); 324 init_gear(&gears[2], 1.3, 2.0, 0.5, 10, 0.7); 325} 326 327 328/* new window size or exposure */ 329static void 330gears_reshape(int width, int height) 331{ 332 GLfloat h = (GLfloat) height / (GLfloat) width; 333 334 glViewport(0, 0, (GLint) width, (GLint) height); 335 336 glMatrixMode(GL_PROJECTION); 337 glLoadIdentity(); 338 glFrustumf(-1.0, 1.0, -h, h, 5.0, 60.0); 339 340 glMatrixMode(GL_MODELVIEW); 341 glLoadIdentity(); 342 glTranslatef(0.0, 0.0, -40.0); 343} 344 345 346static void 347gears_idle(void) 348{ 349 static double t0 = -1.; 350 double dt, t = eglutGet(EGLUT_ELAPSED_TIME) / 1000.0; 351 if (t0 < 0.0) 352 t0 = t; 353 dt = t - t0; 354 t0 = t; 355 356 angle += 70.0 * dt; /* 70 degrees per second */ 357 angle = fmod(angle, 360.0); /* prevents eventual overflow */ 358 359 eglutPostRedisplay(); 360} 361 362 363int 364main(int argc, char *argv[]) 365{ 366 eglutInitWindowSize(300, 300); 367 eglutInitAPIMask(EGLUT_OPENGL_ES1_BIT); 368 eglutInit(argc, argv); 369 370 eglutCreateWindow("gears"); 371 372 eglutIdleFunc(gears_idle); 373 eglutReshapeFunc(gears_reshape); 374 eglutDisplayFunc(gears_draw); 375 376 gears_init(); 377 378 eglutMainLoop(); 379 380 gears_fini(); 381 382 return 0; 383} 384