2 * Copyright (C) 2009 Chia-I Wu <olv@0xlab.org>
5 * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
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:
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
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.
34 #define M_PI 3.14159265
46 static GLfloat view_rotx
= 20.0, view_roty
= 30.0, view_rotz
= 0.0;
47 static struct gear gears
[3];
48 static GLfloat angle
= 0.0;
51 * Initialize a gear wheel.
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
61 init_gear(struct gear
*gear
, GLfloat inner_radius
, GLfloat outer_radius
,
62 GLfloat width
, GLint teeth
, GLfloat tooth_depth
)
66 GLint verts_per_tooth
, total_verts
, total_size
;
71 r1
= outer_radius
- tooth_depth
/ 2.0;
72 r2
= outer_radius
+ tooth_depth
/ 2.0;
74 a0
= 2.0 * M_PI
/ teeth
;
78 gear
->vertices
= NULL
;
79 gear
->stride
= sizeof(GLfloat
) * 6; /* XYZ + normal */
80 gear
->num_teeth
= teeth
;
82 verts_per_tooth
= 10 + 4;
83 total_verts
= teeth
* verts_per_tooth
;
84 total_size
= total_verts
* gear
->stride
;
86 verts
= malloc(total_size
);
88 printf("failed to allocate vertices\n");
92 #define GEAR_VERT(r, n, sign) \
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]; \
104 for (i
= 0; i
< teeth
; i
++) {
106 GLfloat vx
[5], vy
[5];
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
);
124 /* outward faces of a tooth, 10 verts */
128 GEAR_VERT(r1
, 0, -1);
130 u
= r2
* vx
[1] - r1
* vx
[0];
131 v
= r2
* vy
[1] - r1
* vy
[0];
135 GEAR_VERT(r2
, 1, -1);
140 GEAR_VERT(r2
, 2, -1);
142 u
= r1
* vx
[3] - r2
* vx
[2];
143 v
= r1
* vy
[3] - r2
* vy
[2];
147 GEAR_VERT(r1
, 3, -1);
152 GEAR_VERT(r1
, 4, -1);
154 /* inside radius cylinder, 4 verts */
158 GEAR_VERT(r0
, 4, -1);
163 GEAR_VERT(r0
, 0, -1);
165 assert(count
% verts_per_tooth
== 0);
167 assert(count
== total_verts
);
170 gear
->vertices
= verts
;
173 glGenBuffers(1, &gear
->vbo
);
175 glBindBuffer(GL_ARRAY_BUFFER
, gear
->vbo
);
176 glBufferData(GL_ARRAY_BUFFER
, total_size
, verts
, GL_STATIC_DRAW
);
182 draw_gear(const struct gear
*gear
)
186 if (!gear
->vbo
&& !gear
->vertices
) {
187 printf("nothing to be drawn\n");
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));
196 glBindBuffer(GL_ARRAY_BUFFER
, 0);
197 glVertexPointer(3, GL_FLOAT
, gear
->stride
, gear
->vertices
);
198 glNormalPointer(GL_FLOAT
, gear
->stride
, gear
->vertices
+ 3);
201 glEnableClientState(GL_VERTEX_ARRAY
);
203 for (i
= 0; i
< gear
->num_teeth
; i
++) {
204 const GLint base
= (10 + 4) * i
;
207 glShadeModel(GL_FLAT
);
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;
218 glNormal3f(0.0, 0.0, 1.0);
219 glDrawElements(GL_TRIANGLE_FAN
, 7, GL_UNSIGNED_SHORT
, indices
);
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;
230 glNormal3f(0.0, 0.0, -1.0);
231 glDrawElements(GL_TRIANGLE_FAN
, 7, GL_UNSIGNED_SHORT
, indices
);
233 glEnableClientState(GL_NORMAL_ARRAY
);
235 /* outward face of a tooth */
236 glDrawArrays(GL_TRIANGLE_STRIP
, base
, 10);
238 /* inside radius cylinder */
239 glShadeModel(GL_SMOOTH
);
240 glDrawArrays(GL_TRIANGLE_STRIP
, base
+ 10, 4);
242 glDisableClientState(GL_NORMAL_ARRAY
);
245 glDisableClientState(GL_VERTEX_ARRAY
);
250 gears_draw(void *data
)
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 };
256 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
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);
264 glTranslatef(-3.0, -2.0, 0.0);
265 glRotatef(angle
, 0.0, 0.0, 1.0);
267 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, red
);
268 draw_gear(&gears
[0]);
273 glTranslatef(3.1, -2.0, 0.0);
274 glRotatef(-2.0 * angle
- 9.0, 0.0, 0.0, 1.0);
276 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, green
);
277 draw_gear(&gears
[1]);
282 glTranslatef(-3.1, 4.2, 0.0);
283 glRotatef(-2.0 * angle
- 25.0, 0.0, 0.0, 1.0);
285 glMaterialfv(GL_FRONT_AND_BACK
, GL_AMBIENT_AND_DIFFUSE
, blue
);
286 draw_gear(&gears
[2]);
292 /* advance rotation for next frame */
293 angle
+= 0.5; /* 0.5 degree per frame */
299 static void gears_fini(void)
302 for (i
= 0; i
< 3; i
++) {
303 struct gear
*gear
= &gears
[i
];
305 glDeleteBuffers(1, &gear
->vbo
);
308 if (gear
->vertices
) {
309 free(gear
->vertices
);
310 gear
->vertices
= NULL
;
316 static void gears_init(void)
318 static const GLfloat pos
[4] = { 5.0, 5.0, 10.0, 0.0 };
320 glLightfv(GL_LIGHT0
, GL_POSITION
, pos
);
321 glEnable(GL_CULL_FACE
);
322 glEnable(GL_LIGHTING
);
324 glEnable(GL_DEPTH_TEST
);
325 glEnable(GL_NORMALIZE
);
327 init_gear(&gears
[0], 1.0, 4.0, 1.0, 20, 0.7);
328 init_gear(&gears
[1], 0.5, 2.0, 2.0, 10, 0.7);
329 init_gear(&gears
[2], 1.3, 2.0, 0.5, 10, 0.7);
333 /* new window size or exposure */
335 gears_reshape(int width
, int height
)
337 GLfloat h
= (GLfloat
) height
/ (GLfloat
) width
;
339 glViewport(0, 0, (GLint
) width
, (GLint
) height
);
341 glMatrixMode(GL_PROJECTION
);
343 glFrustumf(-1.0, 1.0, -h
, h
, 5.0, 60.0);
345 glMatrixMode(GL_MODELVIEW
);
347 glTranslatef(0.0, 0.0, -40.0);
351 static void gears_run(void)
353 winsysRun(5.0, gears_draw
, NULL
);
358 main(int argc
, char *argv
[])
360 EGLint width
, height
;
362 if (!winsysInitScreen())
364 winsysQueryScreenSize(&width
, &height
);
367 gears_reshape(width
, height
);