2 * Simple engine demo (crankshaft, pistons, connecting rods)
12 #include <glad/glad.h>
13 #include "glut_wrap.h"
15 #include "trackball.h"
19 #define M_PI 3.14159265358979323846
22 #define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.0)
24 #define TEXTURE_FILE DEMOS_DATA_DIR "reflect.rgb"
26 /* Target engine speed: */
27 const int RPM
= 100.0;
45 float CrankPlateThickness
;
47 float CrankJournalRadius
;
48 float CrankJournalLength
;
49 float ConnectingRodLength
;
50 float ConnectingRodThickness
;
51 /* display list IDs */
63 /* When mouse is moving: */
64 GLboolean Rotating
, Translating
;
95 static GLfloat Theta
= 0.0;
97 static const GLfloat PistonColor
[4] = { 1.0, 0.5, 0.5, 1.0 };
98 static const GLfloat ConnRodColor
[4] = { 0.7, 1.0, 0.7, 1.0 };
99 static const GLfloat CrankshaftColor
[4] = { 0.7, 0.7, 1.0, 1.0 };
100 static const GLfloat BlockColor
[4] = {0.8, 0.8, 0.8, 0.75 };
102 static GLuint TextureObj
;
103 static GLint WinWidth
= 800, WinHeight
= 500;
105 static ViewInfo View
;
106 static RenderInfo Render
;
108 #define NUM_ENGINES 3
109 static Engine Engines
[NUM_ENGINES
] =
116 0.5, /* PistonRadius */
117 0.6, /* PistonHeight */
118 0.1, /* WristPinRadius */
120 0.2, /* CrankPlateThickness */
121 0.25, /* CrankPinRadius */
122 0.3, /* CrankJournalRadius */
123 0.4, /* CrankJournalLength */
124 1.5, /* ConnectingRodLength */
125 0.1, /* ConnectingRodThickness */
136 0.5, /* PistonRadius */
137 0.6, /* PistonHeight */
138 0.1, /* WristPinRadius */
140 0.2, /* CrankPlateThickness */
141 0.25, /* CrankPinRadius */
142 0.3, /* CrankJournalRadius */
143 0.4, /* CrankJournalLength */
144 1.5, /* ConnectingRodLength */
145 0.1, /* ConnectingRodThickness */
156 0.5, /* PistonRadius */
157 0.6, /* PistonHeight */
158 0.1, /* WristPinRadius */
160 0.2, /* CrankPlateThickness */
161 0.25, /* CrankPinRadius */
162 0.3, /* CrankJournalRadius */
163 0.4, /* CrankJournalLength */
164 1.5, /* ConnectingRodLength */
165 0.1, /* ConnectingRodThickness */
173 static int CurEngine
= 0;
178 InitViewInfo(ViewInfo
*view
)
180 view
->Rotating
= GL_FALSE
;
181 view
->Translating
= GL_FALSE
;
182 view
->StartX
= view
->StartY
= 0;
183 view
->Distance
= 12.0;
184 view
->StartDistance
= 0.0;
185 view
->CurQuat
[0] = -0.194143;
186 view
->CurQuat
[1] = 0.507848;
187 view
->CurQuat
[2] = 0.115245;
188 view
->CurQuat
[3] = 0.831335;
193 InitRenderInfo(RenderInfo
*render
)
196 render
->Anim
= GL_TRUE
;
197 render
->Wireframe
= GL_FALSE
;
198 render
->Blend
= GL_FALSE
;
199 render
->Antialias
= GL_FALSE
;
200 render
->Texture
= GL_FALSE
;
201 render
->DrawBox
= GL_FALSE
;
202 render
->ShowInfo
= GL_TRUE
;
203 render
->ShowBlock
= GL_FALSE
;
204 render
->UseLists
= GL_FALSE
;
209 * Set GL for given rendering mode.
212 SetRenderState(RenderMode mode
)
214 static const GLfloat gray2
[4] = { 0.2, 0.2, 0.2, 1.0 };
215 static const GLfloat gray4
[4] = { 0.4, 0.4, 0.4, 1.0 };
218 glDisable(GL_LIGHTING
);
219 glDisable(GL_TEXTURE_2D
);
221 glDisable(GL_LINE_SMOOTH
);
222 glPolygonMode(GL_FRONT_AND_BACK
, GL_FILL
);
223 glDisable(GL_TEXTURE_GEN_S
);
224 glDisable(GL_TEXTURE_GEN_T
);
225 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, gray2
);
229 glEnable(GL_LIGHTING
);
232 glPolygonMode(GL_FRONT_AND_BACK
, GL_LINE
);
233 glEnable(GL_LINE_SMOOTH
);
238 glEnable(GL_LIGHTING
);
239 glEnable(GL_TEXTURE_2D
);
240 glEnable(GL_TEXTURE_GEN_S
);
241 glEnable(GL_TEXTURE_GEN_T
);
242 glLightModelfv(GL_LIGHT_MODEL_AMBIENT
, gray4
);
251 * Animate the engine parts.
256 /* convert degrees per millisecond to RPM: */
257 const float m
= 360.0 / 1000.0 / 60.0;
258 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
259 Theta
= ((int) (t
* RPM
* m
)) % 360;
265 * Compute piston's position along its stroke.
268 PistonStrokePosition(float throwDist
, float crankAngle
, float connRodLength
)
270 float x
= throwDist
* cos(DEG_TO_RAD(crankAngle
));
271 float y
= throwDist
* sin(DEG_TO_RAD(crankAngle
));
272 float pos
= y
+ sqrt(connRodLength
* connRodLength
- x
* x
);
278 * Compute position of nth piston along the crankshaft.
281 PistonShaftPosition(const Engine
*eng
, int piston
)
283 const int i
= piston
/ (eng
->Pistons
/ eng
->Cranks
);
285 assert(piston
< eng
->Pistons
);
286 z
= 1.5 * eng
->CrankJournalLength
+ eng
->CrankPlateThickness
287 + i
* (2.0 * (eng
->CrankJournalLength
+ eng
->CrankPlateThickness
));
288 if (eng
->Pistons
> eng
->Cranks
) {
290 z
+= eng
->ConnectingRodThickness
;
292 z
-= eng
->ConnectingRodThickness
;
299 * Compute distance between two adjacent pistons
302 PistonSpacing(const Engine
*eng
)
304 const int pistonsPerCrank
= eng
->Pistons
/ eng
->Cranks
;
305 const float z0
= PistonShaftPosition(eng
, 0);
306 const float z1
= PistonShaftPosition(eng
, pistonsPerCrank
);
312 * (x0, y0) = position of big end on crankshaft
313 * (x1, y1) = position of small end on piston
316 ComputeConnectingRodPosition(float throwDist
, float crankAngle
,
318 float *x0
, float *y0
, float *x1
, float *y1
)
320 *x0
= throwDist
* cos(DEG_TO_RAD(crankAngle
));
321 *y0
= throwDist
* sin(DEG_TO_RAD(crankAngle
));
323 *y1
= PistonStrokePosition(throwDist
, crankAngle
, connRodLength
);
328 * Compute total length of the crankshaft.
331 CrankshaftLength(const Engine
*eng
)
333 float len
= (eng
->Cranks
* 2 + 1) * eng
->CrankJournalLength
334 + 2 * eng
->Cranks
* eng
->CrankPlateThickness
;
341 * Axis of piston = Z axis. Wrist pin is centered on (0, 0, 0).
344 DrawPiston(const Engine
*eng
)
346 const int slices
= 30, stacks
= 4, loops
= 4;
347 const float innerRadius
= 0.9 * eng
->PistonRadius
;
348 const float innerHeight
= eng
->PistonHeight
- 0.15;
349 const float wristPinLength
= 1.8 * eng
->PistonRadius
;
354 glTranslatef(0, 0, -1.1 * eng
->WristPinRadius
);
356 gluQuadricOrientation(Q
, GLU_INSIDE
);
359 gluDisk(Q
, innerRadius
, eng
->PistonRadius
, slices
, 1/*loops*/);
362 gluCylinder(Q
, innerRadius
, innerRadius
, innerHeight
, slices
, stacks
);
366 glTranslatef(0, 0, innerHeight
);
367 gluDisk(Q
, 0, innerRadius
, slices
, loops
);
370 gluQuadricOrientation(Q
, GLU_OUTSIDE
);
373 gluCylinder(Q
, eng
->PistonRadius
, eng
->PistonRadius
, eng
->PistonHeight
,
377 glTranslatef(0, 0, eng
->PistonHeight
);
378 gluDisk(Q
, 0, eng
->PistonRadius
, slices
, loops
);
384 glTranslatef(0, 0.5 * wristPinLength
, 0.0);
385 glRotatef(90, 1, 0, 0);
386 gluCylinder(Q
, eng
->WristPinRadius
, eng
->WristPinRadius
, wristPinLength
,
393 * Draw piston at particular position.
396 DrawPositionedPiston(const Engine
*eng
, float crankAngle
)
398 const float pos
= PistonStrokePosition(eng
->Throw
, crankAngle
,
399 eng
->ConnectingRodLength
);
401 glRotatef(-90, 1, 0, 0);
402 glTranslatef(0, 0, pos
);
404 glCallList(eng
->PistonList
);
412 * Draw connector plate. Used for crankshaft and connecting rods.
415 DrawConnector(float length
, float thickness
,
416 float bigEndRadius
, float smallEndRadius
)
418 const float bigRadius
= 1.2 * bigEndRadius
;
419 const float smallRadius
= 1.2 * smallEndRadius
;
420 const float z0
= -0.5 * thickness
, z1
= -z0
;
421 GLfloat points
[36][2], normals
[36][2];
424 /* compute vertex locations, normals */
425 for (i
= 0; i
< 36; i
++) {
426 const int angle
= i
* 10;
427 float x
= cos(DEG_TO_RAD(angle
));
428 float y
= sin(DEG_TO_RAD(angle
));
431 if (angle
>= 0 && angle
<= 180) {
433 y
= y
* smallRadius
+ length
;
446 for (i
= 0; i
< 36; i
++) {
447 glVertex3f(points
[i
][0], points
[i
][1], z1
);
452 glNormal3f(0, 0, -1);
454 for (i
= 0; i
< 36; i
++) {
455 glVertex3f(points
[35-i
][0], points
[35-i
][1], z0
);
460 glBegin(GL_QUAD_STRIP
);
461 for (i
= 0; i
<= 36; i
++) {
462 const int j
= i
% 36;
463 glNormal3f(normals
[j
][0], normals
[j
][1], 0);
464 glVertex3f(points
[j
][0], points
[j
][1], z1
);
465 glVertex3f(points
[j
][0], points
[j
][1], z0
);
472 * Draw a crankshaft. Shaft lies along +Z axis, starting at zero.
475 DrawCrankshaft(const Engine
*eng
)
477 const int slices
= 20, stacks
= 2;
478 const int n
= eng
->Cranks
* 4 + 1;
479 const float phiStep
= 360 / eng
->Cranks
;
484 for (i
= 0; i
< n
; i
++) {
486 glTranslatef(0, 0, z
);
488 /* draw a crank plate */
489 glRotatef(phi
, 0, 0, 1);
490 glTranslatef(0, 0, 0.5 * eng
->CrankPlateThickness
);
491 DrawConnector(eng
->Throw
, eng
->CrankPlateThickness
,
492 eng
->CrankJournalRadius
, eng
->CrankPinRadius
);
497 else if (i
% 4 == 0) {
498 /* draw crank journal segment */
499 gluCylinder(Q
, eng
->CrankJournalRadius
, eng
->CrankJournalRadius
,
500 eng
->CrankJournalLength
, slices
, stacks
);
501 z
+= eng
->CrankJournalLength
;
503 else if (i
% 4 == 2) {
504 /* draw crank pin segment */
505 glRotatef(phi
, 0, 0, 1);
506 glTranslatef(0, eng
->Throw
, 0);
507 gluCylinder(Q
, eng
->CrankPinRadius
, eng
->CrankPinRadius
,
508 eng
->CrankJournalLength
, slices
, stacks
);
509 z
+= eng
->CrankJournalLength
;
517 * Draw crankshaft at a particular rotation.
518 * \param crankAngle current crankshaft rotation, in radians
521 DrawPositionedCrankshaft(const Engine
*eng
, float crankAngle
)
524 glRotatef(crankAngle
, 0, 0, 1);
526 glCallList(eng
->CrankList
);
534 * Draw a connecting rod at particular position.
535 * \param eng description of connecting rod to draw
536 * \param crankAngle current crankshaft rotation, in radians
539 DrawPositionedConnectingRod(const Engine
*eng
, float crankAngle
)
541 float x0
, y0
, x1
, y1
;
544 ComputeConnectingRodPosition(eng
->Throw
, crankAngle
,
545 eng
->ConnectingRodLength
,
547 d
= sqrt(eng
->ConnectingRodLength
* eng
->ConnectingRodLength
- x0
* x0
);
548 phi
= atan(x0
/ d
) * 180.0 / M_PI
;
551 glTranslatef(x0
, y0
, 0);
552 glRotatef(phi
, 0, 0, 1);
553 if (eng
->ConnRodList
)
554 glCallList(eng
->ConnRodList
);
556 DrawConnector(eng
->ConnectingRodLength
, eng
->ConnectingRodThickness
,
557 eng
->CrankPinRadius
, eng
->WristPinRadius
);
563 * Draw a square with a hole in middle.
566 SquareWithHole(float squareSize
, float holeRadius
)
569 glBegin(GL_QUAD_STRIP
);
571 for (i
= 0; i
<= 360; i
+= 5) {
572 const float x1
= holeRadius
* cos(DEG_TO_RAD(i
));
573 const float y1
= holeRadius
* sin(DEG_TO_RAD(i
));
574 float x2
= 0.0F
, y2
= 0.0F
;
575 if (i
> 315 || i
<= 45) {
577 y2
= squareSize
* tan(DEG_TO_RAD(i
));
579 else if (i
> 45 && i
<= 135) {
580 x2
= -squareSize
* tan(DEG_TO_RAD(i
- 90));
583 else if (i
> 135 && i
<= 225) {
585 y2
= -squareSize
* tan(DEG_TO_RAD(i
-180));
587 else if (i
> 225 && i
<= 315) {
588 x2
= squareSize
* tan(DEG_TO_RAD(i
- 270));
591 glVertex2f(x1
, y1
); /* inner circle */
592 glVertex2f(x2
, y2
); /* outer square */
599 * Draw block with hole through middle.
600 * Hole is centered on Z axis.
601 * Bottom of block is at z=0, top of block is at z = blockHeight.
602 * index is in [0, count - 1] to determine which block faces are drawn.
605 DrawBlockWithHole(float blockSize
, float blockHeight
, float holeRadius
,
606 int index
, int count
)
608 const int slices
= 30, stacks
= 4;
609 const float x
= blockSize
;
610 const float y
= blockSize
;
612 const float z1
= blockHeight
;
614 assert(index
< count
);
616 gluQuadricOrientation(Q
, GLU_INSIDE
);
621 glVertex3f( x
, -y
, z0
);
622 glVertex3f( x
, y
, z0
);
623 glVertex3f( x
, y
, z1
);
624 glVertex3f( x
, -y
, z1
);
626 glNormal3f(-1, 0, 0);
627 glVertex3f(-x
, -y
, z1
);
628 glVertex3f(-x
, y
, z1
);
629 glVertex3f(-x
, y
, z0
);
630 glVertex3f(-x
, -y
, z0
);
634 glVertex3f(-x
, y
, z1
);
635 glVertex3f( x
, y
, z1
);
636 glVertex3f( x
, y
, z0
);
637 glVertex3f(-x
, y
, z0
);
639 if (index
== count
- 1) {
641 glNormal3f(0, -1, 0);
642 glVertex3f(-x
, -y
, z0
);
643 glVertex3f( x
, -y
, z0
);
644 glVertex3f( x
, -y
, z1
);
645 glVertex3f(-x
, -y
, z1
);
649 /* cylinder / hole */
650 gluCylinder(Q
, holeRadius
, holeRadius
, blockHeight
, slices
, stacks
);
654 glRotatef(180, 1, 0, 0);
655 SquareWithHole(blockSize
, holeRadius
);
659 glTranslatef(0, 0, z1
);
660 SquareWithHole(blockSize
, holeRadius
);
662 gluQuadricOrientation(Q
, GLU_OUTSIDE
);
667 * Draw the engine block.
670 DrawEngineBlock(const Engine
*eng
)
672 const float blockHeight
= eng
->Throw
+ 1.5 * eng
->PistonHeight
;
673 const float cylRadius
= 1.01 * eng
->PistonRadius
;
674 const float blockSize
= 0.5 * PistonSpacing(eng
);
675 const int pistonsPerCrank
= eng
->Pistons
/ eng
->Cranks
;
678 for (i
= 0; i
< eng
->Pistons
; i
++) {
679 const float z
= PistonShaftPosition(eng
, i
);
680 const int crank
= i
/ pistonsPerCrank
;
684 glTranslatef(0, 0, z
);
686 /* additional rotation for kth piston per crank */
687 k
= i
% pistonsPerCrank
;
688 glRotatef(k
* -eng
->V_Angle
, 0, 0, 1);
691 glRotatef(-90, 1, 0, 0);
692 glTranslatef(0, 0, eng
->Throw
* 2);
693 DrawBlockWithHole(blockSize
, blockHeight
, cylRadius
,
701 * Generate display lists for engine parts.
704 GenerateDisplayLists(Engine
*eng
)
706 eng
->CrankList
= glGenLists(1);
707 glNewList(eng
->CrankList
, GL_COMPILE
);
711 eng
->ConnRodList
= glGenLists(1);
712 glNewList(eng
->ConnRodList
, GL_COMPILE
);
713 DrawConnector(eng
->ConnectingRodLength
, eng
->ConnectingRodThickness
,
714 eng
->CrankPinRadius
, eng
->WristPinRadius
);
717 eng
->PistonList
= glGenLists(1);
718 glNewList(eng
->PistonList
, GL_COMPILE
);
722 eng
->BlockList
= glGenLists(1);
723 glNewList(eng
->BlockList
, GL_COMPILE
);
724 DrawEngineBlock(eng
);
730 * Free engine display lists (render with immediate mode).
733 FreeDisplayLists(Engine
*eng
)
735 glDeleteLists(eng
->CrankList
, 1);
737 glDeleteLists(eng
->ConnRodList
, 1);
738 eng
->ConnRodList
= 0;
739 glDeleteLists(eng
->PistonList
, 1);
741 glDeleteLists(eng
->BlockList
, 1);
747 * Draw complete engine.
748 * \param eng description of engine to draw
749 * \param crankAngle current crankshaft angle, in radians
752 DrawEngine(const Engine
*eng
, float crankAngle
)
754 const float crankDelta
= 360.0 / eng
->Cranks
;
755 const float crankLen
= CrankshaftLength(eng
);
756 const int pistonsPerCrank
= eng
->Pistons
/ eng
->Cranks
;
760 glRotatef(eng
->V_Angle
* 0.5, 0, 0, 1);
761 glTranslatef(0, 0, -0.5 * crankLen
);
764 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, CrankshaftColor
);
765 glColor4fv(CrankshaftColor
);
766 DrawPositionedCrankshaft(eng
, crankAngle
);
768 for (i
= 0; i
< eng
->Pistons
; i
++) {
769 const float z
= PistonShaftPosition(eng
, i
);
770 const int crank
= i
/ pistonsPerCrank
;
771 float rot
= crankAngle
+ crank
* crankDelta
;
775 glTranslatef(0, 0, z
);
777 /* additional rotation for kth piston per crank */
778 k
= i
% pistonsPerCrank
;
779 glRotatef(k
* -eng
->V_Angle
, 0, 0, 1);
780 rot
+= k
* eng
->V_Angle
;
783 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, PistonColor
);
784 glColor4fv(PistonColor
);
785 DrawPositionedPiston(eng
, rot
);
788 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, ConnRodColor
);
789 glColor4fv(ConnRodColor
);
790 DrawPositionedConnectingRod(eng
, rot
);
794 if (Render
.ShowBlock
) {
795 const GLboolean blend
= glIsEnabled(GL_BLEND
);
797 glDepthMask(GL_FALSE
);
801 glEnable(GL_CULL_FACE
);
803 glMaterialfv(GL_FRONT
, GL_AMBIENT_AND_DIFFUSE
, BlockColor
);
804 glColor4fv(BlockColor
);
806 glCallList(eng
->BlockList
);
808 DrawEngineBlock(eng
);
810 glDisable(GL_CULL_FACE
);
811 glDepthMask(GL_TRUE
);
824 const float xmin
= -3.0, xmax
= 3.0;
825 const float ymin
= -1.0, ymax
= 3.0;
826 const float zmin
= -4.0, zmax
= 4.0;
827 const float step
= 0.5;
828 const float d
= 0.01;
830 GLboolean lit
= glIsEnabled(GL_LIGHTING
);
831 GLboolean tex
= glIsEnabled(GL_TEXTURE_2D
);
833 glDisable(GL_LIGHTING
);
834 glDisable(GL_TEXTURE_2D
);
841 for (x
= xmin
; x
<= xmax
; x
+= step
) {
842 glVertex3f(x
, ymin
, zmin
);
843 glVertex3f(x
, ymax
, zmin
);
847 for (y
= ymin
; y
<= ymax
; y
+= step
) {
848 glVertex3f(xmin
, y
, zmin
);
849 glVertex3f(xmax
, y
, zmin
);
855 for (x
= xmin
; x
<= xmax
; x
+= step
) {
856 glVertex3f(x
, ymin
, zmin
);
857 glVertex3f(x
, ymin
, zmax
);
861 for (z
= zmin
; z
<= zmax
; z
+= step
) {
862 glVertex3f(xmin
, ymin
, z
);
863 glVertex3f(xmax
, ymin
, z
);
869 for (y
= ymin
; y
<= ymax
; y
+= step
) {
870 glVertex3f(xmin
, y
, zmin
);
871 glVertex3f(xmin
, y
, zmax
);
875 for (z
= zmin
; z
<= zmax
; z
+= step
) {
876 glVertex3f(xmin
, ymin
, z
);
877 glVertex3f(xmin
, ymax
, z
);
881 glColor3f(0.4, 0.4, 0.6);
884 glVertex3f(xmin
-d
, ymin
, zmin
);
885 glVertex3f(xmin
-d
, ymax
, zmin
);
886 glVertex3f(xmin
-d
, ymax
, zmax
);
887 glVertex3f(xmin
-d
, ymin
, zmax
);
889 glVertex3f(xmin
, ymin
-d
, zmin
);
890 glVertex3f(xmax
, ymin
-d
, zmin
);
891 glVertex3f(xmax
, ymin
-d
, zmax
);
892 glVertex3f(xmin
, ymin
-d
, zmax
);
894 glVertex3f(xmin
, ymin
, zmin
-d
);
895 glVertex3f(xmax
, ymin
, zmin
-d
);
896 glVertex3f(xmax
, ymax
, zmin
-d
);
897 glVertex3f(xmin
, ymax
, zmin
-d
);
901 glEnable(GL_LIGHTING
);
903 glEnable(GL_TEXTURE_2D
);
908 PrintString(const char *s
)
911 glutBitmapCharacter(GLUT_BITMAP_8_BY_13
, (int) *s
);
920 static double t0
= -1.0;
921 static int frames
= 0;
922 double t
= glutGet(GLUT_ELAPSED_TIME
) / 1000.0;
931 else if (t
- t0
>= 1.0) {
932 fps
= (int) (frames
/ (t
- t0
) + 0.5);
947 glClear(GL_COLOR_BUFFER_BIT
| GL_DEPTH_BUFFER_BIT
);
951 glTranslatef(0.0, 0.0, -View
.Distance
);
952 build_rotmatrix(rot
, View
.CurQuat
);
953 glMultMatrixf(&rot
[0][0]);
956 glTranslatef(0, -0.75, 0);
959 DrawEngine(Engines
+ CurEngine
, Theta
);
965 if (Render
.ShowInfo
) {
966 GLboolean lit
= glIsEnabled(GL_LIGHTING
);
967 GLboolean tex
= glIsEnabled(GL_TEXTURE_2D
);
969 sprintf(s
, "%s %d FPS %s", Engines
[CurEngine
].Name
, fps
,
970 Render
.UseLists
? "Display Lists" : "Immediate mode");
971 glDisable(GL_LIGHTING
);
972 glDisable(GL_TEXTURE_2D
);
974 glWindowPos2iARB(10, 10);
977 glEnable(GL_LIGHTING
);
979 glEnable(GL_TEXTURE_2D
);
982 /* also print out a periodic fps to stdout. useful for trying to
983 * figure out the performance impact of rendering the string above
988 static GLint Frames
= 0;
989 GLint t
= glutGet(GLUT_ELAPSED_TIME
);
993 if (t
- T0
>= 5000) {
994 GLfloat seconds
= (t
- T0
) / 1000.0;
995 GLfloat fps
= Frames
/ seconds
;
996 printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames
, seconds
, fps
);
1009 * Handle window resize.
1012 Reshape(int width
, int height
)
1014 float ar
= (float) width
/ height
;
1016 glViewport(0, 0, width
, height
);
1017 glMatrixMode(GL_PROJECTION
);
1019 glFrustum(-ar
* s
, ar
* s
, -s
, s
, 2.0, 50.0);
1020 glMatrixMode(GL_MODELVIEW
);
1028 * Handle mouse button.
1031 Mouse(int button
, int state
, int x
, int y
)
1033 if (button
== GLUT_LEFT_BUTTON
) {
1034 if (state
== GLUT_DOWN
) {
1037 View
.Rotating
= GL_TRUE
;
1039 else if (state
== GLUT_UP
) {
1040 View
.Rotating
= GL_FALSE
;
1043 else if (button
== GLUT_MIDDLE_BUTTON
) {
1044 if (state
== GLUT_DOWN
) {
1047 View
.StartDistance
= View
.Distance
;
1048 View
.Translating
= GL_TRUE
;
1050 else if (state
== GLUT_UP
) {
1051 View
.Translating
= GL_FALSE
;
1058 * Handle mouse motion
1061 Motion(int x
, int y
)
1064 if (View
.Rotating
) {
1065 float x0
= (2.0 * View
.StartX
- WinWidth
) / WinWidth
;
1066 float y0
= (WinHeight
- 2.0 * View
.StartY
) / WinHeight
;
1067 float x1
= (2.0 * x
- WinWidth
) / WinWidth
;
1068 float y1
= (WinHeight
- 2.0 * y
) / WinHeight
;
1071 trackball(q
, x0
, y0
, x1
, y1
);
1074 for (i
= 0; i
< 1; i
++)
1075 add_quats(q
, View
.CurQuat
, View
.CurQuat
);
1077 glutPostRedisplay();
1079 else if (View
.Translating
) {
1080 float dz
= 0.01 * (y
- View
.StartY
);
1081 View
.Distance
= View
.StartDistance
+ dz
;
1082 glutPostRedisplay();
1094 Render
.Anim
= !Render
.Anim
;
1102 OptChangeEngine(void)
1104 CurEngine
= (CurEngine
+ 1) % NUM_ENGINES
;
1111 if (Render
.Mode
> TEXTURED
)
1113 SetRenderState(Render
.Mode
);
1117 OptDisplayLists(void)
1120 Render
.UseLists
= !Render
.UseLists
;
1121 if (Render
.UseLists
) {
1122 for (i
= 0; i
< NUM_ENGINES
; i
++) {
1123 GenerateDisplayLists(Engines
+ i
);
1127 for (i
= 0; i
< NUM_ENGINES
; i
++) {
1128 FreeDisplayLists(Engines
+ i
);
1136 Render
.ShowBlock
= !Render
.ShowBlock
;
1142 Render
.ShowInfo
= !Render
.ShowInfo
;
1148 Render
.DrawBox
= !Render
.DrawBox
;
1160 glutDestroyWindow(Win
);
1166 * Define menu entries (w/ keyboard shortcuts)
1173 void (*Function
)(void);
1176 static const MenuInfo MenuItems
[] = {
1177 { "Animation", 'a', OptAnimation
},
1178 { "Change Engine", 'e', OptChangeEngine
},
1179 { "Rendering Style", 'm', OptRenderMode
},
1180 { "Display Lists", 'd', OptDisplayLists
},
1181 { "Show Block", 'b', OptShowBlock
},
1182 { "Show Info", 'i', OptShowInfo
},
1183 { "Show Box", 'x', OptShowBox
},
1184 { "Exit", 27, OptExit
},
1185 { NULL
, 'r', OptRotate
},
1191 * Handle menu selection.
1194 MenuHandler(int entry
)
1196 MenuItems
[entry
].Function();
1197 glutPostRedisplay();
1208 glutCreateMenu(MenuHandler
);
1209 for (i
= 0; MenuItems
[i
].Text
; i
++) {
1210 glutAddMenuEntry(MenuItems
[i
].Text
, i
);
1212 glutAttachMenu(GLUT_RIGHT_BUTTON
);
1217 * Handle keyboard event.
1220 Key(unsigned char key
, int x
, int y
)
1224 for (i
= 0; MenuItems
[i
].Key
; i
++) {
1225 if (MenuItems
[i
].Key
== key
) {
1226 MenuItems
[i
].Function();
1227 glutPostRedisplay();
1235 void LoadTexture(void)
1237 GLboolean convolve
= GL_FALSE
;
1239 glGenTextures(1, &TextureObj
);
1240 glBindTexture(GL_TEXTURE_2D
, TextureObj
);
1241 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MIN_FILTER
, GL_LINEAR
);
1242 glTexParameteri(GL_TEXTURE_2D
, GL_TEXTURE_MAG_FILTER
, GL_LINEAR
);
1243 glTexGeni(GL_S
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
1244 glTexGeni(GL_T
, GL_TEXTURE_GEN_MODE
, GL_SPHERE_MAP
);
1247 #define FILTER_SIZE 7
1248 /* use convolution to blur the texture to simulate a dull finish
1254 GLfloat filter
[FILTER_SIZE
][FILTER_SIZE
][4];
1256 for (h
= 0; h
< FILTER_SIZE
; h
++) {
1257 for (w
= 0; w
< FILTER_SIZE
; w
++) {
1258 const GLfloat k
= 1.0 / (FILTER_SIZE
* FILTER_SIZE
);
1259 filter
[h
][w
][0] = k
;
1260 filter
[h
][w
][1] = k
;
1261 filter
[h
][w
][2] = k
;
1262 filter
[h
][w
][3] = k
;
1266 glEnable(GL_CONVOLUTION_2D
);
1267 glConvolutionParameteri(GL_CONVOLUTION_2D
,
1268 GL_CONVOLUTION_BORDER_MODE
, GL_CONSTANT_BORDER
);
1269 glConvolutionFilter2D(GL_CONVOLUTION_2D
, GL_RGBA
,
1270 FILTER_SIZE
, FILTER_SIZE
,
1271 GL_RGBA
, GL_FLOAT
, filter
);
1273 img
= LoadRGBImage(TEXTURE_FILE
, &w
, &h
, &format
);
1275 printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE
);
1279 glTexImage2D(GL_TEXTURE_2D
, 0, GL_RGB
, w
, h
, 0,
1280 format
, GL_UNSIGNED_BYTE
, img
);
1284 if (!LoadRGBMipmaps(TEXTURE_FILE
, GL_RGB
)) {
1285 printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE
);
1295 const GLfloat lightColor
[4] = { 0.7, 0.7, 0.7, 1.0 };
1296 const GLfloat specular
[4] = { 0.8, 0.8, 0.8, 1.0 };
1297 const GLfloat backColor
[4] = { 1, 1, 0, 0 };
1299 Q
= gluNewQuadric();
1300 gluQuadricNormals(Q
, GLU_SMOOTH
);
1304 glClearColor(0.3, 0.3, 0.3, 0.0);
1305 glEnable(GL_DEPTH_TEST
);
1306 glEnable(GL_LIGHTING
);
1307 glEnable(GL_LIGHT0
);
1308 glLightfv(GL_LIGHT0
, GL_DIFFUSE
, lightColor
);
1309 glMaterialf(GL_FRONT
, GL_SHININESS
, 40);
1310 glMaterialfv(GL_FRONT
, GL_SPECULAR
, specular
);
1311 glEnable(GL_NORMALIZE
);
1313 glMaterialfv(GL_BACK
, GL_DIFFUSE
, backColor
);
1315 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE
, 1);
1317 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
1319 InitViewInfo(&View
);
1320 InitRenderInfo(&Render
);
1325 main(int argc
, char *argv
[])
1327 glutInitWindowSize(WinWidth
, WinHeight
);
1328 glutInit(&argc
, argv
);
1329 glutInitDisplayMode(GLUT_RGB
| GLUT_DOUBLE
| GLUT_DEPTH
);
1330 Win
= glutCreateWindow("OpenGL Engine Demo");
1332 glutReshapeFunc(Reshape
);
1333 glutMouseFunc(Mouse
);
1334 glutMotionFunc(Motion
);
1335 glutKeyboardFunc(Key
);
1336 glutDisplayFunc(Draw
);