132001f49Smrg/* 232001f49Smrg * Copyright (C) 2009 Chia-I Wu <olv@0xlab.org> 332001f49Smrg * 432001f49Smrg * Based on eglgears by 532001f49Smrg * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. 632001f49Smrg * 732001f49Smrg * Permission is hereby granted, free of charge, to any person obtaining a 832001f49Smrg * copy of this software and associated documentation files (the "Software"), 932001f49Smrg * to deal in the Software without restriction, including without limitation 1032001f49Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 1132001f49Smrg * and/or sell copies of the Software, and to permit persons to whom the 1232001f49Smrg * Software is furnished to do so, subject to the following conditions: 1332001f49Smrg * 1432001f49Smrg * The above copyright notice and this permission notice shall be included 1532001f49Smrg * in all copies or substantial portions of the Software. 1632001f49Smrg * 1732001f49Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 1832001f49Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1932001f49Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 2032001f49Smrg * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 2132001f49Smrg * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2232001f49Smrg * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 2332001f49Smrg */ 2432001f49Smrg 2532001f49Smrg#include <stdlib.h> 2632001f49Smrg#include <stdio.h> 2732001f49Smrg#include <math.h> 2832001f49Smrg#include <assert.h> 2932001f49Smrg 3032001f49Smrg#include <GLES/gl.h> 3132001f49Smrg#include "eglut.h" 3232001f49Smrg 3332001f49Smrg#ifndef M_PI 3432001f49Smrg#define M_PI 3.14159265 3532001f49Smrg#endif 3632001f49Smrg 3732001f49Smrg 3832001f49Smrgstruct gear { 3932001f49Smrg GLuint vbo; 4032001f49Smrg GLfloat *vertices; 4132001f49Smrg GLsizei stride; 4232001f49Smrg 4332001f49Smrg GLint num_teeth; 4432001f49Smrg}; 4532001f49Smrg 4632001f49Smrgstatic GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; 4732001f49Smrgstatic struct gear gears[3]; 4832001f49Smrgstatic GLfloat angle = 0.0; 4932001f49Smrg 5032001f49Smrg/* 5132001f49Smrg * Initialize a gear wheel. 5232001f49Smrg * 5332001f49Smrg * Input: gear - gear to initialize 5432001f49Smrg * inner_radius - radius of hole at center 5532001f49Smrg * outer_radius - radius at center of teeth 5632001f49Smrg * width - width of gear 5732001f49Smrg * teeth - number of teeth 5832001f49Smrg * tooth_depth - depth of tooth 5932001f49Smrg */ 6032001f49Smrgstatic void 6132001f49Smrginit_gear(struct gear *gear, GLfloat inner_radius, GLfloat outer_radius, 6232001f49Smrg GLfloat width, GLint teeth, GLfloat tooth_depth) 6332001f49Smrg{ 6432001f49Smrg GLfloat r0, r1, r2; 6532001f49Smrg GLfloat a0, da; 6632001f49Smrg GLint verts_per_tooth, total_verts, total_size; 6732001f49Smrg GLint count, i; 6832001f49Smrg GLfloat *verts; 6932001f49Smrg 7032001f49Smrg r0 = inner_radius; 7132001f49Smrg r1 = outer_radius - tooth_depth / 2.0; 7232001f49Smrg r2 = outer_radius + tooth_depth / 2.0; 7332001f49Smrg 7432001f49Smrg a0 = 2.0 * M_PI / teeth; 7532001f49Smrg da = a0 / 4.0; 7632001f49Smrg 7732001f49Smrg gear->vbo = 0; 7832001f49Smrg gear->vertices = NULL; 7932001f49Smrg gear->stride = sizeof(GLfloat) * 6; /* XYZ + normal */ 8032001f49Smrg gear->num_teeth = teeth; 8132001f49Smrg 8232001f49Smrg verts_per_tooth = 10 + 4; 8332001f49Smrg total_verts = teeth * verts_per_tooth; 8432001f49Smrg total_size = total_verts * gear->stride; 8532001f49Smrg 8632001f49Smrg verts = malloc(total_size); 8732001f49Smrg if (!verts) { 8832001f49Smrg printf("failed to allocate vertices\n"); 8932001f49Smrg return; 9032001f49Smrg } 9132001f49Smrg 9232001f49Smrg#define GEAR_VERT(r, n, sign) \ 9332001f49Smrg do { \ 9432001f49Smrg verts[count * 6 + 0] = (r) * vx[n]; \ 9532001f49Smrg verts[count * 6 + 1] = (r) * vy[n]; \ 9632001f49Smrg verts[count * 6 + 2] = (sign) * width * 0.5; \ 9732001f49Smrg verts[count * 6 + 3] = normal[0]; \ 9832001f49Smrg verts[count * 6 + 4] = normal[1]; \ 9932001f49Smrg verts[count * 6 + 5] = normal[2]; \ 10032001f49Smrg count++; \ 10132001f49Smrg } while (0) 10232001f49Smrg 10332001f49Smrg count = 0; 10432001f49Smrg for (i = 0; i < teeth; i++) { 10532001f49Smrg GLfloat normal[3]; 10632001f49Smrg GLfloat vx[5], vy[5]; 10732001f49Smrg GLfloat u, v; 10832001f49Smrg 10932001f49Smrg normal[0] = 0.0; 11032001f49Smrg normal[1] = 0.0; 11132001f49Smrg normal[2] = 0.0; 11232001f49Smrg 11332001f49Smrg vx[0] = cos(i * a0 + 0 * da); 11432001f49Smrg vy[0] = sin(i * a0 + 0 * da); 11532001f49Smrg vx[1] = cos(i * a0 + 1 * da); 11632001f49Smrg vy[1] = sin(i * a0 + 1 * da); 11732001f49Smrg vx[2] = cos(i * a0 + 2 * da); 11832001f49Smrg vy[2] = sin(i * a0 + 2 * da); 11932001f49Smrg vx[3] = cos(i * a0 + 3 * da); 12032001f49Smrg vy[3] = sin(i * a0 + 3 * da); 12132001f49Smrg vx[4] = cos(i * a0 + 4 * da); 12232001f49Smrg vy[4] = sin(i * a0 + 4 * da); 12332001f49Smrg 12432001f49Smrg /* outward faces of a tooth, 10 verts */ 12532001f49Smrg normal[0] = vx[0]; 12632001f49Smrg normal[1] = vy[0]; 12732001f49Smrg GEAR_VERT(r1, 0, 1); 12832001f49Smrg GEAR_VERT(r1, 0, -1); 12932001f49Smrg 13032001f49Smrg u = r2 * vx[1] - r1 * vx[0]; 13132001f49Smrg v = r2 * vy[1] - r1 * vy[0]; 13232001f49Smrg normal[0] = v; 13332001f49Smrg normal[1] = -u; 13432001f49Smrg GEAR_VERT(r2, 1, 1); 13532001f49Smrg GEAR_VERT(r2, 1, -1); 13632001f49Smrg 13732001f49Smrg normal[0] = vx[0]; 13832001f49Smrg normal[1] = vy[0]; 13932001f49Smrg GEAR_VERT(r2, 2, 1); 14032001f49Smrg GEAR_VERT(r2, 2, -1); 14132001f49Smrg 14232001f49Smrg u = r1 * vx[3] - r2 * vx[2]; 14332001f49Smrg v = r1 * vy[3] - r2 * vy[2]; 14432001f49Smrg normal[0] = v; 14532001f49Smrg normal[1] = -u; 14632001f49Smrg GEAR_VERT(r1, 3, 1); 14732001f49Smrg GEAR_VERT(r1, 3, -1); 14832001f49Smrg 14932001f49Smrg normal[0] = vx[0]; 15032001f49Smrg normal[1] = vy[0]; 15132001f49Smrg GEAR_VERT(r1, 4, 1); 15232001f49Smrg GEAR_VERT(r1, 4, -1); 15332001f49Smrg 15432001f49Smrg /* inside radius cylinder, 4 verts */ 15532001f49Smrg normal[0] = -vx[4]; 15632001f49Smrg normal[1] = -vy[4]; 15732001f49Smrg GEAR_VERT(r0, 4, 1); 15832001f49Smrg GEAR_VERT(r0, 4, -1); 15932001f49Smrg 16032001f49Smrg normal[0] = -vx[0]; 16132001f49Smrg normal[1] = -vy[0]; 16232001f49Smrg GEAR_VERT(r0, 0, 1); 16332001f49Smrg GEAR_VERT(r0, 0, -1); 16432001f49Smrg 16532001f49Smrg assert(count % verts_per_tooth == 0); 16632001f49Smrg } 16732001f49Smrg assert(count == total_verts); 16832001f49Smrg#undef GEAR_VERT 16932001f49Smrg 17032001f49Smrg gear->vertices = verts; 17132001f49Smrg 17232001f49Smrg /* setup VBO */ 17332001f49Smrg glGenBuffers(1, &gear->vbo); 17432001f49Smrg if (gear->vbo) { 17532001f49Smrg glBindBuffer(GL_ARRAY_BUFFER, gear->vbo); 17632001f49Smrg glBufferData(GL_ARRAY_BUFFER, total_size, verts, GL_STATIC_DRAW); 17732001f49Smrg } 17832001f49Smrg} 17932001f49Smrg 18032001f49Smrg 18132001f49Smrgstatic void 18232001f49Smrgdraw_gear(const struct gear *gear) 18332001f49Smrg{ 18432001f49Smrg GLint i; 18532001f49Smrg 18632001f49Smrg if (!gear->vbo && !gear->vertices) { 18732001f49Smrg printf("nothing to be drawn\n"); 18832001f49Smrg return; 18932001f49Smrg } 19032001f49Smrg 19132001f49Smrg if (gear->vbo) { 19232001f49Smrg glBindBuffer(GL_ARRAY_BUFFER, gear->vbo); 19332001f49Smrg glVertexPointer(3, GL_FLOAT, gear->stride, (const GLvoid *) 0); 19432001f49Smrg glNormalPointer(GL_FLOAT, gear->stride, (const GLvoid *) (sizeof(GLfloat) * 3)); 19532001f49Smrg } else { 19632001f49Smrg glBindBuffer(GL_ARRAY_BUFFER, 0); 19732001f49Smrg glVertexPointer(3, GL_FLOAT, gear->stride, gear->vertices); 19832001f49Smrg glNormalPointer(GL_FLOAT, gear->stride, gear->vertices + 3); 19932001f49Smrg } 20032001f49Smrg 20132001f49Smrg glEnableClientState(GL_VERTEX_ARRAY); 20232001f49Smrg 20332001f49Smrg for (i = 0; i < gear->num_teeth; i++) { 20432001f49Smrg const GLint base = (10 + 4) * i; 20532001f49Smrg GLushort indices[7]; 20632001f49Smrg 20732001f49Smrg glShadeModel(GL_FLAT); 20832001f49Smrg 20932001f49Smrg /* front face */ 21032001f49Smrg indices[0] = base + 12; 21132001f49Smrg indices[1] = base + 0; 21232001f49Smrg indices[2] = base + 2; 21332001f49Smrg indices[3] = base + 4; 21432001f49Smrg indices[4] = base + 6; 21532001f49Smrg indices[5] = base + 8; 21632001f49Smrg indices[6] = base + 10; 21732001f49Smrg 21832001f49Smrg glNormal3f(0.0, 0.0, 1.0); 21932001f49Smrg glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices); 22032001f49Smrg 22132001f49Smrg /* back face */ 22232001f49Smrg indices[0] = base + 13; 22332001f49Smrg indices[1] = base + 11; 22432001f49Smrg indices[2] = base + 9; 22532001f49Smrg indices[3] = base + 7; 22632001f49Smrg indices[4] = base + 5; 22732001f49Smrg indices[5] = base + 3; 22832001f49Smrg indices[6] = base + 1; 22932001f49Smrg 23032001f49Smrg glNormal3f(0.0, 0.0, -1.0); 23132001f49Smrg glDrawElements(GL_TRIANGLE_FAN, 7, GL_UNSIGNED_SHORT, indices); 23232001f49Smrg 23332001f49Smrg glEnableClientState(GL_NORMAL_ARRAY); 23432001f49Smrg 23532001f49Smrg /* outward face of a tooth */ 23632001f49Smrg glDrawArrays(GL_TRIANGLE_STRIP, base, 10); 23732001f49Smrg 23832001f49Smrg /* inside radius cylinder */ 23932001f49Smrg glShadeModel(GL_SMOOTH); 24032001f49Smrg glDrawArrays(GL_TRIANGLE_STRIP, base + 10, 4); 24132001f49Smrg 24232001f49Smrg glDisableClientState(GL_NORMAL_ARRAY); 24332001f49Smrg } 24432001f49Smrg 24532001f49Smrg glDisableClientState(GL_VERTEX_ARRAY); 24632001f49Smrg} 24732001f49Smrg 24832001f49Smrg 24932001f49Smrgstatic void 25032001f49Smrggears_draw(void) 25132001f49Smrg{ 25232001f49Smrg static const GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; 25332001f49Smrg static const GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; 25432001f49Smrg static const GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; 25532001f49Smrg 25632001f49Smrg glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 25732001f49Smrg 25832001f49Smrg glPushMatrix(); 25932001f49Smrg glRotatef(view_rotx, 1.0, 0.0, 0.0); 26032001f49Smrg glRotatef(view_roty, 0.0, 1.0, 0.0); 26132001f49Smrg glRotatef(view_rotz, 0.0, 0.0, 1.0); 26232001f49Smrg 26332001f49Smrg glPushMatrix(); 26432001f49Smrg glTranslatef(-3.0, -2.0, 0.0); 26532001f49Smrg glRotatef(angle, 0.0, 0.0, 1.0); 26632001f49Smrg 26732001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red); 26832001f49Smrg draw_gear(&gears[0]); 26932001f49Smrg 27032001f49Smrg glPopMatrix(); 27132001f49Smrg 27232001f49Smrg glPushMatrix(); 27332001f49Smrg glTranslatef(3.1, -2.0, 0.0); 27432001f49Smrg glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); 27532001f49Smrg 27632001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green); 27732001f49Smrg draw_gear(&gears[1]); 27832001f49Smrg 27932001f49Smrg glPopMatrix(); 28032001f49Smrg 28132001f49Smrg glPushMatrix(); 28232001f49Smrg glTranslatef(-3.1, 4.2, 0.0); 28332001f49Smrg glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); 28432001f49Smrg 28532001f49Smrg glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue); 28632001f49Smrg draw_gear(&gears[2]); 28732001f49Smrg 28832001f49Smrg glPopMatrix(); 28932001f49Smrg 29032001f49Smrg glPopMatrix(); 29132001f49Smrg} 29232001f49Smrg 29332001f49Smrg 29432001f49Smrgstatic void gears_fini(void) 29532001f49Smrg{ 29632001f49Smrg GLint i; 29732001f49Smrg for (i = 0; i < 3; i++) { 29832001f49Smrg struct gear *gear = &gears[i]; 29932001f49Smrg if (gear->vbo) { 30032001f49Smrg glDeleteBuffers(1, &gear->vbo); 30132001f49Smrg gear->vbo = 0; 30232001f49Smrg } 30332001f49Smrg if (gear->vertices) { 30432001f49Smrg free(gear->vertices); 30532001f49Smrg gear->vertices = NULL; 30632001f49Smrg } 30732001f49Smrg } 30832001f49Smrg} 30932001f49Smrg 31032001f49Smrg 31132001f49Smrgstatic void gears_init(void) 31232001f49Smrg{ 31332001f49Smrg static const GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; 31432001f49Smrg 31532001f49Smrg glLightfv(GL_LIGHT0, GL_POSITION, pos); 31632001f49Smrg glEnable(GL_CULL_FACE); 31732001f49Smrg glEnable(GL_LIGHTING); 31832001f49Smrg glEnable(GL_LIGHT0); 31932001f49Smrg glEnable(GL_DEPTH_TEST); 32032001f49Smrg glEnable(GL_NORMALIZE); 32132001f49Smrg 32232001f49Smrg init_gear(&gears[0], 1.0, 4.0, 1.0, 20, 0.7); 32332001f49Smrg init_gear(&gears[1], 0.5, 2.0, 2.0, 10, 0.7); 32432001f49Smrg init_gear(&gears[2], 1.3, 2.0, 0.5, 10, 0.7); 32532001f49Smrg} 32632001f49Smrg 32732001f49Smrg 32832001f49Smrg/* new window size or exposure */ 32932001f49Smrgstatic void 33032001f49Smrggears_reshape(int width, int height) 33132001f49Smrg{ 33232001f49Smrg GLfloat h = (GLfloat) height / (GLfloat) width; 33332001f49Smrg 33432001f49Smrg glViewport(0, 0, (GLint) width, (GLint) height); 33532001f49Smrg 33632001f49Smrg glMatrixMode(GL_PROJECTION); 33732001f49Smrg glLoadIdentity(); 33832001f49Smrg glFrustumf(-1.0, 1.0, -h, h, 5.0, 60.0); 33932001f49Smrg 34032001f49Smrg glMatrixMode(GL_MODELVIEW); 34132001f49Smrg glLoadIdentity(); 34232001f49Smrg glTranslatef(0.0, 0.0, -40.0); 34332001f49Smrg} 34432001f49Smrg 34532001f49Smrg 34632001f49Smrgstatic void 34732001f49Smrggears_idle(void) 34832001f49Smrg{ 34932001f49Smrg static double t0 = -1.; 35032001f49Smrg double dt, t = eglutGet(EGLUT_ELAPSED_TIME) / 1000.0; 35132001f49Smrg if (t0 < 0.0) 35232001f49Smrg t0 = t; 35332001f49Smrg dt = t - t0; 35432001f49Smrg t0 = t; 35532001f49Smrg 35632001f49Smrg angle += 70.0 * dt; /* 70 degrees per second */ 35732001f49Smrg angle = fmod(angle, 360.0); /* prevents eventual overflow */ 35832001f49Smrg 35932001f49Smrg eglutPostRedisplay(); 36032001f49Smrg} 36132001f49Smrg 36232001f49Smrg 36332001f49Smrgint 36432001f49Smrgmain(int argc, char *argv[]) 36532001f49Smrg{ 36632001f49Smrg eglutInitWindowSize(300, 300); 36732001f49Smrg eglutInitAPIMask(EGLUT_OPENGL_ES1_BIT); 36832001f49Smrg eglutInit(argc, argv); 36932001f49Smrg 37032001f49Smrg eglutCreateWindow("gears"); 37132001f49Smrg 37232001f49Smrg eglutIdleFunc(gears_idle); 37332001f49Smrg eglutReshapeFunc(gears_reshape); 37432001f49Smrg eglutDisplayFunc(gears_draw); 37532001f49Smrg 37632001f49Smrg gears_init(); 37732001f49Smrg 37832001f49Smrg eglutMainLoop(); 37932001f49Smrg 38032001f49Smrg gears_fini(); 38132001f49Smrg 38232001f49Smrg return 0; 38332001f49Smrg} 384