Clone of mesa.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293
  1. /**
  2. * Simple engine demo (crankshaft, pistons, connecting rods)
  3. *
  4. * Brian Paul
  5. * June 2006
  6. */
  7. #define GL_GLEXT_PROTOTYPES
  8. #include <assert.h>
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <math.h>
  12. #include <GL/glut.h>
  13. #include "readtex.h"
  14. #include "trackball.h"
  15. #define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.0)
  16. #define TEXTURE_FILE "../images/reflect.rgb"
  17. /* Target engine speed: */
  18. const int RPM = 100.0;
  19. /**
  20. * Engine description.
  21. */
  22. typedef struct
  23. {
  24. const char *Name;
  25. int Pistons;
  26. int Cranks;
  27. float V_Angle;
  28. float PistonRadius;
  29. float PistonHeight;
  30. float WristPinRadius;
  31. float Throw;
  32. float CrankPlateThickness;
  33. float CrankPinRadius;
  34. float CrankJournalRadius;
  35. float CrankJournalLength;
  36. float ConnectingRodLength;
  37. float ConnectingRodThickness;
  38. /* display list IDs */
  39. GLuint CrankList;
  40. GLuint ConnRodList;
  41. GLuint PistonList;
  42. GLuint BlockList;
  43. } Engine;
  44. typedef struct
  45. {
  46. float CurQuat[4];
  47. float Distance;
  48. /* When mouse is moving: */
  49. GLboolean Rotating, Translating;
  50. GLint StartX, StartY;
  51. float StartDistance;
  52. } ViewInfo;
  53. typedef enum
  54. {
  55. LIT,
  56. WIREFRAME,
  57. TEXTURED
  58. } RenderMode;
  59. typedef struct
  60. {
  61. RenderMode Mode;
  62. GLboolean Anim;
  63. GLboolean Wireframe;
  64. GLboolean Blend;
  65. GLboolean Antialias;
  66. GLboolean Texture;
  67. GLboolean UseLists;
  68. GLboolean DrawBox;
  69. GLboolean ShowInfo;
  70. GLboolean ShowBlock;
  71. } RenderInfo;
  72. static GLUquadric *Q;
  73. static GLfloat Theta = 0.0;
  74. static const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
  75. static const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
  76. static const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
  77. static const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 };
  78. static GLuint TextureObj;
  79. static GLint WinWidth = 800, WinHeight = 500;
  80. static ViewInfo View;
  81. static RenderInfo Render;
  82. #define NUM_ENGINES 3
  83. static Engine Engines[NUM_ENGINES] =
  84. {
  85. {
  86. "V-6",
  87. 6, /* Pistons */
  88. 3, /* Cranks */
  89. 90.0, /* V_Angle */
  90. 0.5, /* PistonRadius */
  91. 0.6, /* PistonHeight */
  92. 0.1, /* WristPinRadius */
  93. 0.5, /* Throw */
  94. 0.2, /* CrankPlateThickness */
  95. 0.25, /* CrankPinRadius */
  96. 0.3, /* CrankJournalRadius */
  97. 0.4, /* CrankJournalLength */
  98. 1.5, /* ConnectingRodLength */
  99. 0.1 /* ConnectingRodThickness */
  100. },
  101. {
  102. "Inline-4",
  103. 4, /* Pistons */
  104. 4, /* Cranks */
  105. 0.0, /* V_Angle */
  106. 0.5, /* PistonRadius */
  107. 0.6, /* PistonHeight */
  108. 0.1, /* WristPinRadius */
  109. 0.5, /* Throw */
  110. 0.2, /* CrankPlateThickness */
  111. 0.25, /* CrankPinRadius */
  112. 0.3, /* CrankJournalRadius */
  113. 0.4, /* CrankJournalLength */
  114. 1.5, /* ConnectingRodLength */
  115. 0.1 /* ConnectingRodThickness */
  116. },
  117. {
  118. "Boxer-6",
  119. 6, /* Pistons */
  120. 3, /* Cranks */
  121. 180.0,/* V_Angle */
  122. 0.5, /* PistonRadius */
  123. 0.6, /* PistonHeight */
  124. 0.1, /* WristPinRadius */
  125. 0.5, /* Throw */
  126. 0.2, /* CrankPlateThickness */
  127. 0.25, /* CrankPinRadius */
  128. 0.3, /* CrankJournalRadius */
  129. 0.4, /* CrankJournalLength */
  130. 1.5, /* ConnectingRodLength */
  131. 0.1 /* ConnectingRodThickness */
  132. }
  133. };
  134. static int CurEngine = 0;
  135. static void
  136. InitViewInfo(ViewInfo *view)
  137. {
  138. view->Rotating = GL_FALSE;
  139. view->Translating = GL_FALSE;
  140. view->StartX = view->StartY = 0;
  141. view->Distance = 12.0;
  142. view->StartDistance = 0.0;
  143. view->CurQuat[0] = -0.194143;
  144. view->CurQuat[1] = 0.507848;
  145. view->CurQuat[2] = 0.115245;
  146. view->CurQuat[3] = 0.831335;
  147. }
  148. static void
  149. InitRenderInfo(RenderInfo *render)
  150. {
  151. render->Mode = LIT;
  152. render->Anim = GL_TRUE;
  153. render->Wireframe = GL_FALSE;
  154. render->Blend = GL_FALSE;
  155. render->Antialias = GL_FALSE;
  156. render->Texture = GL_FALSE;
  157. render->DrawBox = GL_FALSE;
  158. render->ShowInfo = GL_TRUE;
  159. render->ShowBlock = GL_FALSE;
  160. render->UseLists = GL_FALSE;
  161. }
  162. /**
  163. * Set GL for given rendering mode.
  164. */
  165. static void
  166. SetRenderState(RenderMode mode)
  167. {
  168. static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 };
  169. static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 };
  170. /* defaults */
  171. glDisable(GL_LIGHTING);
  172. glDisable(GL_TEXTURE_2D);
  173. glDisable(GL_BLEND);
  174. glDisable(GL_LINE_SMOOTH);
  175. glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  176. glDisable(GL_TEXTURE_GEN_S);
  177. glDisable(GL_TEXTURE_GEN_T);
  178. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2);
  179. switch (mode) {
  180. case LIT:
  181. glEnable(GL_LIGHTING);
  182. break;
  183. case WIREFRAME:
  184. glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  185. glEnable(GL_LINE_SMOOTH);
  186. glEnable(GL_BLEND);
  187. glLineWidth(1.5);
  188. break;
  189. case TEXTURED:
  190. glEnable(GL_LIGHTING);
  191. glEnable(GL_TEXTURE_2D);
  192. glEnable(GL_TEXTURE_GEN_S);
  193. glEnable(GL_TEXTURE_GEN_T);
  194. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4);
  195. break;
  196. default:
  197. ;
  198. }
  199. }
  200. /**
  201. * Animate the engine parts.
  202. */
  203. static void
  204. Idle(void)
  205. {
  206. /* convert degrees per millisecond to RPM: */
  207. const float m = 360.0 / 1000.0 / 60.0;
  208. GLint t = glutGet(GLUT_ELAPSED_TIME);
  209. Theta = ((int) (t * RPM * m)) % 360;
  210. glutPostRedisplay();
  211. }
  212. /**
  213. * Compute piston's position along its stroke.
  214. */
  215. static float
  216. PistonStrokePosition(float throwDist, float crankAngle, float connRodLength)
  217. {
  218. float x = throwDist * cos(DEG_TO_RAD(crankAngle));
  219. float y = throwDist * sin(DEG_TO_RAD(crankAngle));
  220. float pos = y + sqrt(connRodLength * connRodLength - x * x);
  221. return pos;
  222. }
  223. /**
  224. * Compute position of nth piston along the crankshaft.
  225. */
  226. static float
  227. PistonShaftPosition(const Engine *eng, int piston)
  228. {
  229. const int i = piston / (eng->Pistons / eng->Cranks);
  230. float z;
  231. assert(piston < eng->Pistons);
  232. z = 1.5 * eng->CrankJournalLength + eng->CrankPlateThickness
  233. + i * (2.0 * (eng->CrankJournalLength + eng->CrankPlateThickness));
  234. if (eng->Pistons > eng->Cranks) {
  235. if (piston & 1)
  236. z += eng->ConnectingRodThickness;
  237. else
  238. z -= eng->ConnectingRodThickness;
  239. }
  240. return z;
  241. }
  242. /**
  243. * Compute distance between two adjacent pistons
  244. */
  245. static float
  246. PistonSpacing(const Engine *eng)
  247. {
  248. const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  249. const float z0 = PistonShaftPosition(eng, 0);
  250. const float z1 = PistonShaftPosition(eng, pistonsPerCrank);
  251. return z1 - z0;
  252. }
  253. /**
  254. * (x0, y0) = position of big end on crankshaft
  255. * (x1, y1) = position of small end on piston
  256. */
  257. static void
  258. ComputeConnectingRodPosition(float throwDist, float crankAngle,
  259. float connRodLength,
  260. float *x0, float *y0, float *x1, float *y1)
  261. {
  262. *x0 = throwDist * cos(DEG_TO_RAD(crankAngle));
  263. *y0 = throwDist * sin(DEG_TO_RAD(crankAngle));
  264. *x1 = 0.0;
  265. *y1 = PistonStrokePosition(throwDist, crankAngle, connRodLength);
  266. }
  267. /**
  268. * Compute total length of the crankshaft.
  269. */
  270. static float
  271. CrankshaftLength(const Engine *eng)
  272. {
  273. float len = (eng->Cranks * 2 + 1) * eng->CrankJournalLength
  274. + 2 * eng->Cranks * eng->CrankPlateThickness;
  275. return len;
  276. }
  277. /**
  278. * Draw a piston.
  279. * Axis of piston = Z axis. Wrist pin is centered on (0, 0, 0).
  280. */
  281. static void
  282. DrawPiston(const Engine *eng)
  283. {
  284. const int slices = 30, stacks = 4, loops = 4;
  285. const float innerRadius = 0.9 * eng->PistonRadius;
  286. const float innerHeight = eng->PistonHeight - 0.15;
  287. const float wristPinLength = 1.8 * eng->PistonRadius;
  288. assert(Q);
  289. glPushMatrix();
  290. glTranslatef(0, 0, -1.1 * eng->WristPinRadius);
  291. gluQuadricOrientation(Q, GLU_INSIDE);
  292. /* bottom rim */
  293. gluDisk(Q, innerRadius, eng->PistonRadius, slices, 1/*loops*/);
  294. /* inner cylinder */
  295. gluCylinder(Q, innerRadius, innerRadius, innerHeight, slices, stacks);
  296. /* inside top */
  297. glPushMatrix();
  298. glTranslatef(0, 0, innerHeight);
  299. gluDisk(Q, 0, innerRadius, slices, loops);
  300. glPopMatrix();
  301. gluQuadricOrientation(Q, GLU_OUTSIDE);
  302. /* outer cylinder */
  303. gluCylinder(Q, eng->PistonRadius, eng->PistonRadius, eng->PistonHeight,
  304. slices, stacks);
  305. /* top */
  306. glTranslatef(0, 0, eng->PistonHeight);
  307. gluDisk(Q, 0, eng->PistonRadius, slices, loops);
  308. glPopMatrix();
  309. /* wrist pin */
  310. glPushMatrix();
  311. glTranslatef(0, 0.5 * wristPinLength, 0.0);
  312. glRotatef(90, 1, 0, 0);
  313. gluCylinder(Q, eng->WristPinRadius, eng->WristPinRadius, wristPinLength,
  314. slices, stacks);
  315. glPopMatrix();
  316. }
  317. /**
  318. * Draw piston at particular position.
  319. */
  320. static void
  321. DrawPositionedPiston(const Engine *eng, float crankAngle)
  322. {
  323. const float pos = PistonStrokePosition(eng->Throw, crankAngle,
  324. eng->ConnectingRodLength);
  325. glPushMatrix();
  326. glRotatef(-90, 1, 0, 0);
  327. glTranslatef(0, 0, pos);
  328. DrawPiston(eng);
  329. glPopMatrix();
  330. }
  331. /**
  332. * Draw connector plate. Used for crankshaft and connecting rods.
  333. */
  334. static void
  335. DrawConnector(float length, float thickness,
  336. float bigEndRadius, float smallEndRadius)
  337. {
  338. const float bigRadius = 1.2 * bigEndRadius;
  339. const float smallRadius = 1.2 * smallEndRadius;
  340. const float z0 = -0.5 * thickness, z1 = -z0;
  341. GLfloat points[36][2], normals[36][2];
  342. int i;
  343. /* compute vertex locations, normals */
  344. for (i = 0; i < 36; i++) {
  345. const int angle = i * 10;
  346. float x = cos(DEG_TO_RAD(angle));
  347. float y = sin(DEG_TO_RAD(angle));
  348. normals[i][0] = x;
  349. normals[i][1] = y;
  350. if (angle >= 0 && angle <= 180) {
  351. x *= smallRadius;
  352. y = y * smallRadius + length;
  353. }
  354. else {
  355. x *= bigRadius;
  356. y *= bigRadius;
  357. }
  358. points[i][0] = x;
  359. points[i][1] = y;
  360. }
  361. /* front face */
  362. glNormal3f(0, 0, 1);
  363. glBegin(GL_POLYGON);
  364. for (i = 0; i < 36; i++) {
  365. glVertex3f(points[i][0], points[i][1], z1);
  366. }
  367. glEnd();
  368. /* back face */
  369. glNormal3f(0, 0, -1);
  370. glBegin(GL_POLYGON);
  371. for (i = 0; i < 36; i++) {
  372. glVertex3f(points[35-i][0], points[35-i][1], z0);
  373. }
  374. glEnd();
  375. /* edge */
  376. glBegin(GL_QUAD_STRIP);
  377. for (i = 0; i <= 36; i++) {
  378. const int j = i % 36;
  379. glNormal3f(normals[j][0], normals[j][1], 0);
  380. glVertex3f(points[j][0], points[j][1], z0);
  381. glVertex3f(points[j][0], points[j][1], z1);
  382. }
  383. glEnd();
  384. }
  385. /**
  386. * Draw a crankshaft. Shaft lies along +Z axis, starting at zero.
  387. */
  388. static void
  389. DrawCrankshaft(const Engine *eng)
  390. {
  391. const int slices = 20, stacks = 2;
  392. const int n = eng->Cranks * 4 + 1;
  393. const float phiStep = 360 / eng->Cranks;
  394. float phi = -90.0;
  395. int i;
  396. float z = 0.0;
  397. for (i = 0; i < n; i++) {
  398. glPushMatrix();
  399. glTranslatef(0, 0, z);
  400. if (i & 1) {
  401. /* draw a crank plate */
  402. glRotatef(phi, 0, 0, 1);
  403. glTranslatef(0, 0, 0.5 * eng->CrankPlateThickness);
  404. DrawConnector(eng->Throw, eng->CrankPlateThickness,
  405. eng->CrankJournalRadius, eng->CrankPinRadius);
  406. z += 0.2;
  407. if (i % 4 == 3)
  408. phi += phiStep;
  409. }
  410. else if (i % 4 == 0) {
  411. /* draw crank journal segment */
  412. gluCylinder(Q, eng->CrankJournalRadius, eng->CrankJournalRadius,
  413. eng->CrankJournalLength, slices, stacks);
  414. z += eng->CrankJournalLength;
  415. }
  416. else if (i % 4 == 2) {
  417. /* draw crank pin segment */
  418. glRotatef(phi, 0, 0, 1);
  419. glTranslatef(0, eng->Throw, 0);
  420. gluCylinder(Q, eng->CrankPinRadius, eng->CrankPinRadius,
  421. eng->CrankJournalLength, slices, stacks);
  422. z += eng->CrankJournalLength;
  423. }
  424. glPopMatrix();
  425. }
  426. }
  427. /**
  428. * Draw crankshaft at a particular rotation.
  429. * \param crankAngle current crankshaft rotation, in radians
  430. */
  431. static void
  432. DrawPositionedCrankshaft(const Engine *eng, float crankAngle)
  433. {
  434. glPushMatrix();
  435. glRotatef(crankAngle, 0, 0, 1);
  436. if (eng->CrankList)
  437. glCallList(eng->CrankList);
  438. else
  439. DrawCrankshaft(eng);
  440. glPopMatrix();
  441. }
  442. /**
  443. * Draw a connecting rod at particular position.
  444. * \param eng description of connecting rod to draw
  445. * \param crankAngle current crankshaft rotation, in radians
  446. */
  447. static void
  448. DrawPositionedConnectingRod(const Engine *eng, float crankAngle)
  449. {
  450. float x0, y0, x1, y1;
  451. float d, phi;
  452. ComputeConnectingRodPosition(eng->Throw, crankAngle,
  453. eng->ConnectingRodLength,
  454. &x0, &y0, &x1, &y1);
  455. d = sqrt(eng->ConnectingRodLength * eng->ConnectingRodLength - x0 * x0);
  456. phi = atan(x0 / d) * 180.0 / M_PI;
  457. glPushMatrix();
  458. glTranslatef(x0, y0, 0);
  459. glRotatef(phi, 0, 0, 1);
  460. if (eng->ConnRodList)
  461. glCallList(eng->ConnRodList);
  462. else
  463. DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
  464. eng->CrankPinRadius, eng->WristPinRadius);
  465. glPopMatrix();
  466. }
  467. /**
  468. * Draw a square with a hole in middle.
  469. */
  470. static void
  471. SquareWithHole(float squareSize, float holeRadius)
  472. {
  473. int i;
  474. glBegin(GL_QUAD_STRIP);
  475. glNormal3f(0, 0, 1);
  476. for (i = 0; i <= 360; i += 5) {
  477. const float x1 = holeRadius * cos(DEG_TO_RAD(i));
  478. const float y1 = holeRadius * sin(DEG_TO_RAD(i));
  479. float x2, y2;
  480. if (i > 315 || i <= 45) {
  481. x2 = squareSize;
  482. y2 = squareSize * tan(DEG_TO_RAD(i));
  483. }
  484. else if (i > 45 && i <= 135) {
  485. x2 = -squareSize * tan(DEG_TO_RAD(i - 90));
  486. y2 = squareSize;
  487. }
  488. else if (i > 135 && i <= 225) {
  489. x2 = -squareSize;
  490. y2 = -squareSize * tan(DEG_TO_RAD(i-180));
  491. }
  492. else if (i > 225 && i <= 315) {
  493. x2 = squareSize * tan(DEG_TO_RAD(i - 270));
  494. y2 = -squareSize;
  495. }
  496. glVertex2f(x1, y1); /* inner circle */
  497. glVertex2f(x2, y2); /* outer square */
  498. }
  499. glEnd();
  500. }
  501. /**
  502. * Draw block with hole through middle.
  503. * Hole is centered on Z axis.
  504. * Bottom of block is at z=0, top of block is at z = blockHeight.
  505. * index is in [0, count - 1] to determine which block faces are drawn.
  506. */
  507. static void
  508. DrawBlockWithHole(float blockSize, float blockHeight, float holeRadius,
  509. int index, int count)
  510. {
  511. const int slices = 30, stacks = 4;
  512. const float x = blockSize;
  513. const float y = blockSize;
  514. const float z0 = 0;
  515. const float z1 = blockHeight;
  516. assert(index < count);
  517. assert(Q);
  518. gluQuadricOrientation(Q, GLU_INSIDE);
  519. glBegin(GL_QUADS);
  520. /* +X face */
  521. glNormal3f(1, 0, 0);
  522. glVertex3f( x, -y, z0);
  523. glVertex3f( x, y, z0);
  524. glVertex3f( x, y, z1);
  525. glVertex3f( x, -y, z1);
  526. /* -X face */
  527. glNormal3f(-1, 0, 0);
  528. glVertex3f(-x, -y, z1);
  529. glVertex3f(-x, y, z1);
  530. glVertex3f(-x, y, z0);
  531. glVertex3f(-x, -y, z0);
  532. if (index == 0) {
  533. /* +Y face */
  534. glNormal3f(0, 1, 0);
  535. glVertex3f(-x, y, z1);
  536. glVertex3f( x, y, z1);
  537. glVertex3f( x, y, z0);
  538. glVertex3f(-x, y, z0);
  539. }
  540. if (index == count - 1) {
  541. /* -Y face */
  542. glNormal3f(0, -1, 0);
  543. glVertex3f(-x, -y, z0);
  544. glVertex3f( x, -y, z0);
  545. glVertex3f( x, -y, z1);
  546. glVertex3f(-x, -y, z1);
  547. }
  548. glEnd();
  549. /* cylinder / hole */
  550. gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks);
  551. /* face at z0 */
  552. glPushMatrix();
  553. glRotatef(180, 1, 0, 0);
  554. SquareWithHole(blockSize, holeRadius);
  555. glPopMatrix();
  556. /* face at z1 */
  557. glTranslatef(0, 0, z1);
  558. SquareWithHole(blockSize, holeRadius);
  559. gluQuadricOrientation(Q, GLU_OUTSIDE);
  560. }
  561. /**
  562. * Draw the engine block.
  563. */
  564. static void
  565. DrawEngineBlock(const Engine *eng)
  566. {
  567. const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight;
  568. const float cylRadius = 1.01 * eng->PistonRadius;
  569. const float blockSize = 0.5 * PistonSpacing(eng);
  570. const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  571. int i;
  572. for (i = 0; i < eng->Pistons; i++) {
  573. const float z = PistonShaftPosition(eng, i);
  574. const int crank = i / pistonsPerCrank;
  575. int k;
  576. glPushMatrix();
  577. glTranslatef(0, 0, z);
  578. /* additional rotation for kth piston per crank */
  579. k = i % pistonsPerCrank;
  580. glRotatef(k * -eng->V_Angle, 0, 0, 1);
  581. /* the block */
  582. glRotatef(-90, 1, 0, 0);
  583. glTranslatef(0, 0, eng->Throw * 2);
  584. DrawBlockWithHole(blockSize, blockHeight, cylRadius,
  585. crank, eng->Cranks);
  586. glPopMatrix();
  587. }
  588. }
  589. /**
  590. * Generate display lists for engine parts.
  591. */
  592. static void
  593. GenerateDisplayLists(Engine *eng)
  594. {
  595. eng->CrankList = glGenLists(1);
  596. glNewList(eng->CrankList, GL_COMPILE);
  597. DrawCrankshaft(eng);
  598. glEndList();
  599. eng->ConnRodList = glGenLists(1);
  600. glNewList(eng->ConnRodList, GL_COMPILE);
  601. DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
  602. eng->CrankPinRadius, eng->WristPinRadius);
  603. glEndList();
  604. eng->PistonList = glGenLists(1);
  605. glNewList(eng->PistonList, GL_COMPILE);
  606. DrawPiston(eng);
  607. glEndList();
  608. eng->BlockList = glGenLists(1);
  609. glNewList(eng->BlockList, GL_COMPILE);
  610. DrawEngineBlock(eng);
  611. glEndList();
  612. }
  613. /**
  614. * Free engine display lists (render with immediate mode).
  615. */
  616. static void
  617. FreeDisplayLists(Engine *eng)
  618. {
  619. glDeleteLists(eng->CrankList, 1);
  620. eng->CrankList = 0;
  621. glDeleteLists(eng->ConnRodList, 1);
  622. eng->ConnRodList = 0;
  623. glDeleteLists(eng->PistonList, 1);
  624. eng->PistonList = 0;
  625. glDeleteLists(eng->BlockList, 1);
  626. eng->BlockList = 0;
  627. }
  628. /**
  629. * Draw complete engine.
  630. * \param eng description of engine to draw
  631. * \param crankAngle current crankshaft angle, in radians
  632. */
  633. static void
  634. DrawEngine(const Engine *eng, float crankAngle)
  635. {
  636. const float crankDelta = 360.0 / eng->Cranks;
  637. const float crankLen = CrankshaftLength(eng);
  638. const int pistonsPerCrank = eng->Pistons / eng->Cranks;
  639. int i;
  640. glPushMatrix();
  641. glRotatef(eng->V_Angle * 0.5, 0, 0, 1);
  642. glTranslatef(0, 0, -0.5 * crankLen);
  643. /* crankshaft */
  644. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, CrankshaftColor);
  645. glColor4fv(CrankshaftColor);
  646. DrawPositionedCrankshaft(eng, crankAngle);
  647. for (i = 0; i < eng->Pistons; i++) {
  648. const float z = PistonShaftPosition(eng, i);
  649. const int crank = i / pistonsPerCrank;
  650. float rot = crankAngle + crank * crankDelta;
  651. int k;
  652. glPushMatrix();
  653. glTranslatef(0, 0, z);
  654. /* additional rotation for kth piston per crank */
  655. k = i % pistonsPerCrank;
  656. glRotatef(k * -eng->V_Angle, 0, 0, 1);
  657. rot += k * eng->V_Angle;
  658. /* piston */
  659. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, PistonColor);
  660. glColor4fv(PistonColor);
  661. DrawPositionedPiston(eng, rot);
  662. /* connecting rod */
  663. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ConnRodColor);
  664. glColor4fv(ConnRodColor);
  665. DrawPositionedConnectingRod(eng, rot);
  666. glPopMatrix();
  667. }
  668. if (Render.ShowBlock) {
  669. const GLboolean blend = glIsEnabled(GL_BLEND);
  670. glDepthMask(GL_FALSE);
  671. if (!blend) {
  672. glEnable(GL_BLEND);
  673. }
  674. glEnable(GL_CULL_FACE);
  675. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, BlockColor);
  676. glColor4fv(BlockColor);
  677. if (eng->CrankList)
  678. glCallList(eng->BlockList);
  679. else
  680. DrawEngineBlock(eng);
  681. glDisable(GL_CULL_FACE);
  682. glDepthMask(GL_TRUE);
  683. if (!blend) {
  684. glDisable(GL_BLEND);
  685. }
  686. }
  687. glPopMatrix();
  688. }
  689. static void
  690. DrawBox(void)
  691. {
  692. const float xmin = -3.0, xmax = 3.0;
  693. const float ymin = -1.0, ymax = 3.0;
  694. const float zmin = -4.0, zmax = 4.0;
  695. const float step = 0.5;
  696. const float d = 0.01;
  697. float x, y, z;
  698. GLboolean lit = glIsEnabled(GL_LIGHTING);
  699. GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
  700. glDisable(GL_LIGHTING);
  701. glDisable(GL_TEXTURE_2D);
  702. glColor3f(1, 1, 1);
  703. /* Z min */
  704. glBegin(GL_LINES);
  705. for (x = xmin; x <= xmax; x += step) {
  706. glVertex3f(x, ymin, zmin);
  707. glVertex3f(x, ymax, zmin);
  708. }
  709. glEnd();
  710. glBegin(GL_LINES);
  711. for (y = ymin; y <= ymax; y += step) {
  712. glVertex3f(xmin, y, zmin);
  713. glVertex3f(xmax, y, zmin);
  714. }
  715. glEnd();
  716. /* Y min */
  717. glBegin(GL_LINES);
  718. for (x = xmin; x <= xmax; x += step) {
  719. glVertex3f(x, ymin, zmin);
  720. glVertex3f(x, ymin, zmax);
  721. }
  722. glEnd();
  723. glBegin(GL_LINES);
  724. for (z = zmin; z <= zmax; z += step) {
  725. glVertex3f(xmin, ymin, z);
  726. glVertex3f(xmax, ymin, z);
  727. }
  728. glEnd();
  729. /* X min */
  730. glBegin(GL_LINES);
  731. for (y = ymin; y <= ymax; y += step) {
  732. glVertex3f(xmin, y, zmin);
  733. glVertex3f(xmin, y, zmax);
  734. }
  735. glEnd();
  736. glBegin(GL_LINES);
  737. for (z = zmin; z <= zmax; z += step) {
  738. glVertex3f(xmin, ymin, z);
  739. glVertex3f(xmin, ymax, z);
  740. }
  741. glEnd();
  742. glColor3f(0.4, 0.4, 0.6);
  743. glBegin(GL_QUADS);
  744. /* xmin */
  745. glVertex3f(xmin-d, ymin, zmin);
  746. glVertex3f(xmin-d, ymax, zmin);
  747. glVertex3f(xmin-d, ymax, zmax);
  748. glVertex3f(xmin-d, ymin, zmax);
  749. /* ymin */
  750. glVertex3f(xmin, ymin-d, zmin);
  751. glVertex3f(xmax, ymin-d, zmin);
  752. glVertex3f(xmax, ymin-d, zmax);
  753. glVertex3f(xmin, ymin-d, zmax);
  754. /* zmin */
  755. glVertex3f(xmin, ymin, zmin-d);
  756. glVertex3f(xmax, ymin, zmin-d);
  757. glVertex3f(xmax, ymax, zmin-d);
  758. glVertex3f(xmin, ymax, zmin-d);
  759. glEnd();
  760. if (lit)
  761. glEnable(GL_LIGHTING);
  762. if (tex)
  763. glEnable(GL_TEXTURE_2D);
  764. }
  765. static void
  766. PrintString(const char *s)
  767. {
  768. while (*s) {
  769. glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
  770. s++;
  771. }
  772. }
  773. static int
  774. ComputeFPS(void)
  775. {
  776. static double t0 = -1.0;
  777. static int frames = 0;
  778. double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  779. static int fps = 0;
  780. frames++;
  781. if (t0 < 0.0) {
  782. t0 = t;
  783. fps = 0;
  784. }
  785. else if (t - t0 >= 1.0) {
  786. fps = (int) (frames / (t - t0) + 0.5);
  787. t0 = t;
  788. frames = 0;
  789. }
  790. return fps;
  791. }
  792. static void
  793. Draw(void)
  794. {
  795. int fps;
  796. GLfloat rot[4][4];
  797. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  798. glPushMatrix();
  799. glTranslatef(0.0, 0.0, -View.Distance);
  800. build_rotmatrix(rot, View.CurQuat);
  801. glMultMatrixf(&rot[0][0]);
  802. glPushMatrix();
  803. glTranslatef(0, -0.75, 0);
  804. if (Render.DrawBox)
  805. DrawBox();
  806. DrawEngine(Engines + CurEngine, Theta);
  807. glPopMatrix();
  808. glPopMatrix();
  809. fps = ComputeFPS();
  810. if (Render.ShowInfo) {
  811. GLboolean lit = glIsEnabled(GL_LIGHTING);
  812. GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
  813. char s[100];
  814. sprintf(s, "%s %d FPS %s", Engines[CurEngine].Name, fps,
  815. Render.UseLists ? "Display Lists" : "Immediate mode");
  816. glDisable(GL_LIGHTING);
  817. glDisable(GL_TEXTURE_2D);
  818. glColor3f(1, 1 , 1);
  819. glWindowPos2iARB(10, 10);
  820. PrintString(s);
  821. if (lit)
  822. glEnable(GL_LIGHTING);
  823. if (tex)
  824. glEnable(GL_TEXTURE_2D);
  825. }
  826. glutSwapBuffers();
  827. }
  828. /**
  829. * Handle window resize.
  830. */
  831. static void
  832. Reshape(int width, int height)
  833. {
  834. float ar = (float) width / height;
  835. float s = 0.5;
  836. glViewport(0, 0, width, height);
  837. glMatrixMode(GL_PROJECTION);
  838. glLoadIdentity();
  839. glFrustum(-ar * s, ar * s, -s, s, 2.0, 50.0);
  840. glMatrixMode(GL_MODELVIEW);
  841. glLoadIdentity();
  842. WinWidth = width;
  843. WinHeight = height;
  844. }
  845. /**
  846. * Handle mouse button.
  847. */
  848. static void
  849. Mouse(int button, int state, int x, int y)
  850. {
  851. if (button == GLUT_LEFT_BUTTON) {
  852. if (state == GLUT_DOWN) {
  853. View.StartX = x;
  854. View.StartY = y;
  855. View.Rotating = GL_TRUE;
  856. }
  857. else if (state == GLUT_UP) {
  858. View.Rotating = GL_FALSE;
  859. }
  860. }
  861. else if (button == GLUT_MIDDLE_BUTTON) {
  862. if (state == GLUT_DOWN) {
  863. View.StartX = x;
  864. View.StartY = y;
  865. View.StartDistance = View.Distance;
  866. View.Translating = GL_TRUE;
  867. }
  868. else if (state == GLUT_UP) {
  869. View.Translating = GL_FALSE;
  870. }
  871. }
  872. }
  873. /**
  874. * Handle mouse motion
  875. */
  876. static void
  877. Motion(int x, int y)
  878. {
  879. int i;
  880. if (View.Rotating) {
  881. float x0 = (2.0 * View.StartX - WinWidth) / WinWidth;
  882. float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight;
  883. float x1 = (2.0 * x - WinWidth) / WinWidth;
  884. float y1 = (WinHeight - 2.0 * y) / WinHeight;
  885. float q[4];
  886. trackball(q, x0, y0, x1, y1);
  887. View.StartX = x;
  888. View.StartY = y;
  889. for (i = 0; i < 1; i++)
  890. add_quats(q, View.CurQuat, View.CurQuat);
  891. glutPostRedisplay();
  892. }
  893. else if (View.Translating) {
  894. float dz = 0.01 * (y - View.StartY);
  895. View.Distance = View.StartDistance + dz;
  896. glutPostRedisplay();
  897. }
  898. }
  899. /**
  900. ** Menu Callbacks
  901. **/
  902. static void
  903. OptAnimation(void)
  904. {
  905. Render.Anim = !Render.Anim;
  906. if (Render.Anim)
  907. glutIdleFunc(Idle);
  908. else
  909. glutIdleFunc(NULL);
  910. }
  911. static void
  912. OptChangeEngine(void)
  913. {
  914. CurEngine = (CurEngine + 1) % NUM_ENGINES;
  915. }
  916. static void
  917. OptRenderMode(void)
  918. {
  919. Render.Mode++;
  920. if (Render.Mode > TEXTURED)
  921. Render.Mode = 0;
  922. SetRenderState(Render.Mode);
  923. }
  924. static void
  925. OptDisplayLists(void)
  926. {
  927. int i;
  928. Render.UseLists = !Render.UseLists;
  929. if (Render.UseLists) {
  930. for (i = 0; i < NUM_ENGINES; i++) {
  931. GenerateDisplayLists(Engines + i);
  932. }
  933. }
  934. else {
  935. for (i = 0; i < NUM_ENGINES; i++) {
  936. FreeDisplayLists(Engines + i);
  937. }
  938. }
  939. }
  940. static void
  941. OptShowBlock(void)
  942. {
  943. Render.ShowBlock = !Render.ShowBlock;
  944. }
  945. static void
  946. OptShowInfo(void)
  947. {
  948. Render.ShowInfo = !Render.ShowInfo;
  949. }
  950. static void
  951. OptShowBox(void)
  952. {
  953. Render.DrawBox = !Render.DrawBox;
  954. }
  955. static void
  956. OptRotate(void)
  957. {
  958. Theta += 5.0;
  959. }
  960. static void
  961. OptExit(void)
  962. {
  963. exit(0);
  964. }
  965. /**
  966. * Define menu entries (w/ keyboard shortcuts)
  967. */
  968. typedef struct
  969. {
  970. const char *Text;
  971. const char Key;
  972. void (*Function)(void);
  973. } MenuInfo;
  974. static const MenuInfo MenuItems[] = {
  975. { "Animation", 'a', OptAnimation },
  976. { "Change Engine", 'e', OptChangeEngine },
  977. { "Rendering Style", 'm', OptRenderMode },
  978. { "Display Lists", 'd', OptDisplayLists },
  979. { "Show Block", 'b', OptShowBlock },
  980. { "Show Info", 'i', OptShowInfo },
  981. { "Show Box", 'x', OptShowBox },
  982. { "Exit", 27, OptExit },
  983. { NULL, 'r', OptRotate },
  984. { NULL, 0, NULL }
  985. };
  986. /**
  987. * Handle menu selection.
  988. */
  989. static void
  990. MenuHandler(int entry)
  991. {
  992. MenuItems[entry].Function();
  993. glutPostRedisplay();
  994. }
  995. /**
  996. * Make pop-up menu.
  997. */
  998. static void
  999. MakeMenu(void)
  1000. {
  1001. int i;
  1002. glutCreateMenu(MenuHandler);
  1003. for (i = 0; MenuItems[i].Text; i++) {
  1004. glutAddMenuEntry(MenuItems[i].Text, i);
  1005. }
  1006. glutAttachMenu(GLUT_RIGHT_BUTTON);
  1007. }
  1008. /**
  1009. * Handle keyboard event.
  1010. */
  1011. static void
  1012. Key(unsigned char key, int x, int y)
  1013. {
  1014. int i;
  1015. (void) x; (void) y;
  1016. for (i = 0; MenuItems[i].Key; i++) {
  1017. if (MenuItems[i].Key == key) {
  1018. MenuItems[i].Function();
  1019. glutPostRedisplay();
  1020. break;
  1021. }
  1022. }
  1023. }
  1024. static
  1025. void LoadTexture(void)
  1026. {
  1027. GLboolean convolve = GL_FALSE;
  1028. glGenTextures(1, &TextureObj);
  1029. glBindTexture(GL_TEXTURE_2D, TextureObj);
  1030. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1031. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1032. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  1033. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
  1034. if (convolve) {
  1035. #define FILTER_SIZE 7
  1036. /* use convolution to blur the texture to simulate a dull finish
  1037. * on the object.
  1038. */
  1039. GLubyte *img;
  1040. GLenum format;
  1041. GLint w, h;
  1042. GLfloat filter[FILTER_SIZE][FILTER_SIZE][4];
  1043. for (h = 0; h < FILTER_SIZE; h++) {
  1044. for (w = 0; w < FILTER_SIZE; w++) {
  1045. const GLfloat k = 1.0 / (FILTER_SIZE * FILTER_SIZE);
  1046. filter[h][w][0] = k;
  1047. filter[h][w][1] = k;
  1048. filter[h][w][2] = k;
  1049. filter[h][w][3] = k;
  1050. }
  1051. }
  1052. glEnable(GL_CONVOLUTION_2D);
  1053. glConvolutionParameteri(GL_CONVOLUTION_2D,
  1054. GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER);
  1055. glConvolutionFilter2D(GL_CONVOLUTION_2D, GL_RGBA,
  1056. FILTER_SIZE, FILTER_SIZE,
  1057. GL_RGBA, GL_FLOAT, filter);
  1058. img = LoadRGBImage(TEXTURE_FILE, &w, &h, &format);
  1059. if (!img) {
  1060. printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
  1061. exit(1);
  1062. }
  1063. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
  1064. format, GL_UNSIGNED_BYTE, img);
  1065. free(img);
  1066. }
  1067. else {
  1068. if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
  1069. printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
  1070. exit(1);
  1071. }
  1072. }
  1073. }
  1074. static void
  1075. Init(void)
  1076. {
  1077. const GLfloat lightColor[4] = { 0.7, 0.7, 0.7, 1.0 };
  1078. const GLfloat specular[4] = { 0.8, 0.8, 0.8, 1.0 };
  1079. Q = gluNewQuadric();
  1080. gluQuadricNormals(Q, GLU_SMOOTH);
  1081. LoadTexture();
  1082. glClearColor(0.3, 0.3, 0.3, 0.0);
  1083. glEnable(GL_DEPTH_TEST);
  1084. glEnable(GL_LIGHTING);
  1085. glEnable(GL_LIGHT0);
  1086. glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
  1087. glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 40);
  1088. glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
  1089. glEnable(GL_NORMALIZE);
  1090. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1091. InitViewInfo(&View);
  1092. InitRenderInfo(&Render);
  1093. }
  1094. int
  1095. main(int argc, char *argv[])
  1096. {
  1097. glutInit(&argc, argv);
  1098. glutInitWindowSize(WinWidth, WinHeight);
  1099. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  1100. glutCreateWindow("OpenGL Engine Demo");
  1101. glutReshapeFunc(Reshape);
  1102. glutMouseFunc(Mouse);
  1103. glutMotionFunc(Motion);
  1104. glutKeyboardFunc(Key);
  1105. glutDisplayFunc(Draw);
  1106. MakeMenu();
  1107. Init();
  1108. if (Render.Anim)
  1109. glutIdleFunc(Idle);
  1110. glutMainLoop();
  1111. return 0;
  1112. }