PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/taoframework-2.1.0/source/examples/NateRobins/Maiden.cs

#
C# | 719 lines | 566 code | 60 blank | 93 comment | 69 complexity | e8a7f3eeb83f93d2e6f994fb565f9e79 MD5 | raw file
Possible License(s): MIT, BSD-3-Clause, GPL-2.0
  1. #region License
  2. /*
  3. MIT License
  4. Copyright Š2003-2005 Tao Framework Team
  5. http://www.taoframework.com
  6. All rights reserved.
  7. Permission is hereby granted, free of charge, to any person obtaining a copy
  8. of this software and associated documentation files (the "Software"), to deal
  9. in the Software without restriction, including without limitation the rights
  10. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. copies of the Software, and to permit persons to whom the Software is
  12. furnished to do so, subject to the following conditions:
  13. The above copyright notice and this permission notice shall be included in all
  14. copies or substantial portions of the Software.
  15. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. SOFTWARE.
  22. */
  23. #endregion License
  24. #region Original Credits / License
  25. /*
  26. maiden.c
  27. Nate Robins, 1997
  28. A killer "Iron Maiden rocks out with OpenGL" demo (according to
  29. Mark Kilgard).
  30. */
  31. #endregion Original Credits / License
  32. using System;
  33. using System.IO;
  34. using System.Text;
  35. using System.Text.RegularExpressions;
  36. using Tao.FreeGlut;
  37. using Tao.OpenGl;
  38. namespace NateRobins {
  39. #region Class Documentation
  40. /// <summary>
  41. /// A killer "Iron Maiden rocks out with OpenGL" demo (according to Mark Kilgard).
  42. /// </summary>
  43. /// <remarks>
  44. /// <para>
  45. /// Original Author: Nate Robins
  46. /// http://www.xmission.com/~nate/sgi.html
  47. /// </para>
  48. /// <para>
  49. /// C# Implementation: Randy Ridge
  50. /// http://www.taoframework.com
  51. /// </para>
  52. /// </remarks>
  53. #endregion Class Documentation
  54. public sealed class Maiden {
  55. // --- Fields ---
  56. #region Private Constants
  57. private static int RI = 4; // Inner radius of torus
  58. private static int RO = 8; // Outer radius of torus
  59. private static int COLORS = 12;
  60. private static int NUMBERSTARS = 500;
  61. private static int RANDOMMAX = 0x7fff;
  62. #endregion Private Constants
  63. #region Private Fields
  64. private static Random random = new Random();
  65. private static Star[] stars = new Star[NUMBERSTARS];
  66. private static int lod = 24; // Level of detail
  67. private static float spinX, spinY, spinZ;
  68. private static int numberSpheres = 12;
  69. private static int numberTextures = 4;
  70. private static int mode = Gl.GL_MODULATE; // Modulate, decal
  71. private static int filter = Gl.GL_LINEAR; // Texture filtering mode
  72. private static bool drawBackground = true; // Draw background image?
  73. private static bool drawStars = true; // Draw stars?
  74. private static bool texturing = true; // Texturing?
  75. private static bool performanceTiming; // Performance timing?
  76. private static bool frozen; // Animation frozen?
  77. private static int width, height;
  78. private static int backgroundTexture = 1;
  79. private static int i, start, last, end, step;
  80. private static byte[/*COLORS*/,/*3*/] colors = {
  81. {255, 0, 0},
  82. {255, 128, 0},
  83. {255, 255, 0},
  84. {128, 255, 0},
  85. { 0, 255, 0},
  86. { 0, 255, 128},
  87. { 0, 255, 255},
  88. { 0, 128, 255},
  89. { 0, 0, 255},
  90. {128, 0, 255},
  91. {255, 0, 255},
  92. {255, 0, 128}
  93. };
  94. private static string[] textureNames = {
  95. "NateRobins.Maiden.DeadOne.ppm",
  96. "NateRobins.Maiden.Virus.ppm",
  97. "NateRobins.Maiden.Ace.ppm",
  98. "NateRobins.Maiden.Space.ppm"
  99. };
  100. #endregion Private Fields
  101. #region Private Structs
  102. private struct Star {
  103. public float X, Y;
  104. public float VX, VY;
  105. }
  106. #endregion Private Structs
  107. // --- Entry Point ---
  108. #region Run()
  109. [STAThread]
  110. public static void Run()
  111. {
  112. Glut.glutInit();
  113. Glut.glutInitDisplayMode(Glut.GLUT_DEPTH | Glut.GLUT_DOUBLE | Glut.GLUT_MULTISAMPLE | Glut.GLUT_RGBA);
  114. Glut.glutInitWindowSize(800, 600);
  115. Glut.glutInitWindowPosition(50, 50);
  116. Glut.glutCreateWindow("Maiden");
  117. Glut.glutDisplayFunc(new Glut.DisplayCallback(Display));
  118. Glut.glutKeyboardFunc(new Glut.KeyboardCallback(Keyboard));
  119. Glut.glutIdleFunc(new Glut.IdleCallback(Idle));
  120. Glut.glutReshapeFunc(new Glut.ReshapeCallback(Reshape));
  121. Glut.glutSpecialFunc(new Glut.SpecialCallback(Special));
  122. Glut.glutCreateMenu(new Glut.CreateMenuCallback(Menu));
  123. Glut.glutAddMenuEntry("Toggle texture mapping", (int) 't');
  124. Glut.glutAddMenuEntry("Toggle texture mode", (int) 'm');
  125. Glut.glutAddMenuEntry("Toggle filter mode", (int) 'f');
  126. Glut.glutAddMenuEntry("Toggle performance", (int) 'p');
  127. Glut.glutAddMenuEntry("Toggle background", (int) 'b');
  128. Glut.glutAddMenuEntry("Toggle animation", (int) ' ');
  129. Glut.glutAddMenuEntry("Toggle culling", (int) 'c');
  130. Glut.glutAddMenuEntry("Toggle stars", (int) '*');
  131. Glut.glutAddMenuEntry("Time full frame (no swap)", (int) 'n');
  132. Glut.glutAddMenuEntry("Print pixels/frame", (int) 'r');
  133. Glut.glutAddMenuEntry("", 0);
  134. Glut.glutAddMenuEntry("> and < keys change # of textures", 0);
  135. Glut.glutAddMenuEntry("Arrows up/down change level of detail", 0);
  136. Glut.glutAddMenuEntry("Arrows right/left change # of spheres", 0);
  137. Glut.glutAddMenuEntry("1-4 keys change background image", 0);
  138. Glut.glutAddMenuEntry("", 0);
  139. Glut.glutAddMenuEntry("Quit", (int) 'r');
  140. Glut.glutAttachMenu(Glut.GLUT_RIGHT_BUTTON);
  141. Init();
  142. LoadTextures();
  143. Glut.glutMainLoop();
  144. }
  145. #endregion Run()
  146. // --- Application Methods ---
  147. #region Color(byte color)
  148. private static void Color(byte color) {
  149. int index = COLORS / numberSpheres * color;
  150. Gl.glColor3ub(colors[index, 0], colors[index, 1], colors[index, 2]);
  151. }
  152. #endregion Color(byte color)
  153. #region Init()
  154. private static void Init() {
  155. float[] Ka = {0.2f, 0.2f, 0.2f, 1.0f};
  156. float[] Ks = {1.0f, 1.0f, 1.0f, 1.0f};
  157. Gl.glEnable(Gl.GL_DEPTH_TEST);
  158. Gl.glEnable(Gl.GL_CULL_FACE);
  159. Gl.glEnable(Gl.GL_LIGHTING);
  160. Gl.glEnable(Gl.GL_LIGHT0);
  161. Gl.glEnable(Gl.GL_COLOR_MATERIAL);
  162. Gl.glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA);
  163. Gl.glColorMaterial(Gl.GL_FRONT, Gl.GL_DIFFUSE);
  164. Gl.glMaterialf(Gl.GL_FRONT, Gl.GL_SHININESS, 64);
  165. Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_SPECULAR, Ks);
  166. Gl.glMaterialfv(Gl.GL_FRONT, Gl.GL_AMBIENT, Ka);
  167. Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, filter);
  168. Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, filter);
  169. }
  170. #endregion Init()
  171. #region LoadTextures()
  172. private static void LoadTextures() {
  173. int w = 0;
  174. int h = 0;
  175. byte[] texture;
  176. Gl.glPixelStorei(Gl.GL_UNPACK_ALIGNMENT, 1);
  177. // XXX - RE bug - must enable texture before bind.
  178. Gl.glEnable(Gl.GL_TEXTURE_2D);
  179. for(int i = 0; i < 4; i++) {
  180. Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1);
  181. texture = PpmRead(textureNames[i], ref w, ref h);
  182. Glu.gluBuild2DMipmaps(Gl.GL_TEXTURE_2D, 3, w, h, Gl.GL_RGB, Gl.GL_UNSIGNED_BYTE, texture);
  183. texture = null;
  184. }
  185. /* XXX - RE bug - must enable texture before bind. */
  186. Gl.glDisable(Gl.GL_TEXTURE_2D);
  187. }
  188. #endregion LoadTextures()
  189. #region int Pixels()
  190. private static int Pixels() {
  191. int i, j, n, values;
  192. float ax, ay, bx, by, area, acc = 0;
  193. float[] buffer;
  194. // Calculate the size of the feedback buffer:
  195. // lod * lod * 2 = number of triangles in the torus
  196. // lod * 2 = number of triangles in each cap of a sphere
  197. // lod * (lod - 2) * 2 = number of triangles in latitudinal strips of a sphere
  198. // *8 = 3 vertices (2 values each) + polygon token and a vertex count
  199. // NUMBERSTARS * 5 = line token + 2 vertices (2 values each)
  200. // 5 * 3 = (possibly 5) bitmap tokens + 1 vertex each (2 values each)
  201. buffer = new float[((lod * lod * 2 + (lod * 2 + lod * (lod - 2) * 2) * numberSpheres) * 8 + NUMBERSTARS * 5 + 5 * 3)];
  202. Gl.glFeedbackBuffer((lod * lod * 2 + (lod * 2 + lod * (lod - 2) * 2) * numberSpheres) * 8 + NUMBERSTARS * 5 + 5 * 3, Gl.GL_2D, buffer);
  203. Gl.glRenderMode(Gl.GL_FEEDBACK);
  204. Display();
  205. values = Gl.glRenderMode(Gl.GL_RENDER);
  206. i = 0;
  207. while(i < values) {
  208. if(buffer[i] == Gl.GL_POLYGON_TOKEN) {
  209. i++;
  210. n = (int) buffer[i];
  211. i++;
  212. for(j = 0; j < n - 2; j++) {
  213. ax = buffer[i + 2 + 2 * j] - buffer[i + 0];
  214. ay = buffer[i + 3 + 2 * j] - buffer[i + 1];
  215. bx = buffer[i + 4 + 2 * j] - buffer[i + 0];
  216. by = buffer[i + 5 + 2 * j] - buffer[i + 1];
  217. area = ax * by - bx * ay;
  218. acc += (area < 0) ? -area : area; // -area = backfacing polygon
  219. i += n * 2;
  220. }
  221. }
  222. else if(buffer[i] == Gl.GL_LINE_RESET_TOKEN) {
  223. i++;
  224. // Assume left-to-right horizontal lines
  225. acc += buffer[i + 2] - buffer[i + 0];
  226. i += 4;
  227. }
  228. else if(buffer[i] == Gl.GL_BITMAP_TOKEN) {
  229. i++;
  230. // Skip past bitmap tokens
  231. i += 2;
  232. }
  233. else {
  234. Console.WriteLine("Unknown token found 0x{0:x4} at {1}!", buffer[i], i);
  235. i++;
  236. }
  237. }
  238. buffer = null;
  239. acc /= 2.0f;
  240. return (int) acc;
  241. }
  242. #endregion int Pixels()
  243. #region byte[] PpmRead(string fileName, ref int width, ref int height)
  244. /// <summary>
  245. /// Reads a PPM raw (type P6) file.
  246. /// </summary>
  247. /// <remarks>
  248. /// <para>
  249. /// The PPM file has a header that should look something like:
  250. /// P6
  251. /// # comment
  252. /// width height max_value
  253. /// rgbrgbrgb...
  254. /// </para>
  255. /// <para>
  256. /// "P6" is the magic cookie which identifies the file type and should be the
  257. /// only characters on the first line followed by a carriage return. Any line
  258. /// starting with a # mark will be treated as a comment and discarded. After the
  259. /// magic cookie, three integer values are expected: width, height of the image
  260. /// and the maximum value for a pixel (max_value must be &lt; 256 for PPM raw
  261. /// files). The data section consists of width*height rgb triplets (one byte
  262. /// each) in binary format (i.e., such as that written with fwrite() or
  263. /// equivalent).
  264. /// </para>
  265. /// <para>
  266. /// The rgb data is returned as an array of unsigned chars (packed rgb). The
  267. /// malloc()'d memory should be free()'d by the caller. If an error occurs, an
  268. /// error message is sent to stderr and NULL is returned.
  269. /// </para>
  270. /// </remarks>
  271. private static byte[] PpmRead(string fileName, ref int width, ref int height) {
  272. FileStream file;
  273. BinaryReader reader;
  274. byte[] image;
  275. byte[] head = new byte[70];
  276. int maxValue = 0;
  277. string header = "";
  278. int dataPosition = 0;
  279. try {
  280. if(File.Exists(Path.Combine("Data", fileName))) {
  281. fileName = Path.Combine("Data", fileName);
  282. }
  283. else {
  284. fileName = Path.Combine(Path.Combine(Path.Combine("..", ".."), "Data"), fileName);
  285. }
  286. file = File.Open(fileName, FileMode.Open, FileAccess.Read);
  287. reader = new BinaryReader(file);
  288. // Grab first two chars of the file and make sure that it has the correct
  289. // magic cookie for a raw PPM file.
  290. head = reader.ReadBytes(70);
  291. if(head[0] != (byte) 'P' && head[1] != (byte) '6') {
  292. Console.WriteLine(fileName + ": Not a raw PPM file!");
  293. return null;
  294. }
  295. // Grab the three elements in the header (width, height, maxval).
  296. header = Encoding.ASCII.GetString(head);
  297. // Strip magic
  298. Regex magic = new Regex(@"P6\s*", RegexOptions.Compiled | RegexOptions.Multiline);
  299. Match magicMatch = magic.Match(header);
  300. if(magicMatch.Success) {
  301. header = header.Remove(magicMatch.Groups[0].Index, magicMatch.Groups[0].Length);
  302. dataPosition += magicMatch.Groups[0].Length;
  303. }
  304. Regex comment = new Regex(@"^#.*\s*", RegexOptions.Compiled | RegexOptions.Multiline);
  305. Regex element = new Regex(@"\s*\d*\s*", RegexOptions.Compiled | RegexOptions.Multiline);
  306. // Gather elements
  307. int i = 0;
  308. bool endComments = false;
  309. while(i < 3) {
  310. // Strip comments
  311. if(!endComments) {
  312. Match commentMatch = comment.Match(header);
  313. if(commentMatch.Success) {
  314. header = header.Remove(commentMatch.Groups[0].Index, commentMatch.Groups[0].Length);
  315. dataPosition += commentMatch.Groups[0].Length;
  316. commentMatch = comment.Match(header);
  317. commentMatch.NextMatch();
  318. }
  319. }
  320. Match elementMatch = element.Match(header);
  321. if(elementMatch.Success) {
  322. if(i == 0) {
  323. width = Int32.Parse(elementMatch.Groups[0].ToString().Trim());
  324. }
  325. if(i == 1) {
  326. height = Int32.Parse(elementMatch.Groups[0].ToString().Trim());
  327. }
  328. if(i == 2) {
  329. maxValue = Int32.Parse(elementMatch.Groups[0].ToString().Trim());
  330. }
  331. header = header.Remove(elementMatch.Groups[0].Index, elementMatch.Groups[0].Length);
  332. dataPosition += elementMatch.Groups[0].Length;
  333. elementMatch = element.Match(header);
  334. elementMatch.NextMatch();
  335. endComments = true;
  336. i++;
  337. }
  338. }
  339. reader.Close();
  340. file.Close();
  341. file = File.Open(fileName, FileMode.Open, FileAccess.Read);
  342. reader = new BinaryReader(file);
  343. // Grab all the image data in one fell swoop
  344. image = new byte[width * height * 3];
  345. reader.ReadBytes(dataPosition);
  346. image = reader.ReadBytes(width * height * 3);
  347. reader.Close();
  348. file.Close();
  349. return image;
  350. }
  351. catch(Exception e) {
  352. Console.WriteLine("Error loading PPM file: " + fileName);
  353. Console.WriteLine(e.ToString());
  354. }
  355. return null;
  356. }
  357. #endregion byte[] PpmRead(string fileName, ref int width, ref int height)
  358. #region Sphere(int texture)
  359. private static void Sphere(int texture) {
  360. if(texturing) {
  361. Gl.glBindTexture(Gl.GL_TEXTURE_2D, texture);
  362. Glut.glutSolidSphere(RI, lod, lod);
  363. }
  364. else {
  365. Glut.glutSolidSphere(RI, lod, lod);
  366. }
  367. }
  368. #endregion Sphere(int texture)
  369. // --- Callbacks ---
  370. #region Display()
  371. private static void Display() {
  372. if(performanceTiming) {
  373. start = Glut.glutGet(Glut.GLUT_ELAPSED_TIME);
  374. }
  375. Gl.glClear(Gl.GL_COLOR_BUFFER_BIT | Gl.GL_DEPTH_BUFFER_BIT);
  376. if(drawBackground || drawStars || performanceTiming) {
  377. Gl.glMatrixMode(Gl.GL_PROJECTION);
  378. Gl.glPushMatrix();
  379. Gl.glLoadIdentity();
  380. Gl.glOrtho(0, width, 0, height, -1, 1);
  381. Gl.glMatrixMode(Gl.GL_MODELVIEW);
  382. Gl.glPushMatrix();
  383. Gl.glLoadIdentity();
  384. Gl.glDepthMask(Gl.GL_FALSE);
  385. Gl.glDisable(Gl.GL_DEPTH_TEST);
  386. Gl.glDisable(Gl.GL_LIGHTING);
  387. if(drawBackground) {
  388. Gl.glEnable(Gl.GL_TEXTURE_2D);
  389. Gl.glBindTexture(Gl.GL_TEXTURE_2D, backgroundTexture);
  390. Gl.glColor3ub(255, 255, 255);
  391. Gl.glBegin(Gl.GL_QUADS);
  392. Gl.glTexCoord2i(0, 0);
  393. Gl.glVertex2i(0, 0);
  394. Gl.glTexCoord2i(1, 0);
  395. Gl.glVertex2i(width, 0);
  396. Gl.glTexCoord2i(1, 1);
  397. Gl.glVertex2i(width, height);
  398. Gl.glTexCoord2i(0, 1);
  399. Gl.glVertex2i(0, height);
  400. Gl.glEnd();
  401. Gl.glDisable(Gl.GL_TEXTURE_2D);
  402. }
  403. if(drawStars) {
  404. Gl.glEnable(Gl.GL_BLEND);
  405. Gl.glBegin(Gl.GL_LINES);
  406. for(i = 0; i < NUMBERSTARS; i++) {
  407. stars[i].X += stars[i].VX;
  408. if(stars[i].X < width) {
  409. Gl.glColor4ub(0, 0, 0, 0);
  410. Gl.glVertex2i((int) (stars[i].X - stars[i].VX * 3), (int) stars[i].Y);
  411. Gl.glColor4ub(255, 255, 255, 255);
  412. Gl.glVertex2i((int) stars[i].X, (int) stars[i].Y);
  413. }
  414. else {
  415. stars[i].X = 0;
  416. }
  417. }
  418. Gl.glEnd();
  419. Gl.glDisable(Gl.GL_BLEND);
  420. }
  421. if(performanceTiming) {
  422. float fps = (1.0f / ((float) (end - last) / 1000.0f));
  423. string s = fps.ToString("F1") + " FPS";
  424. Gl.glColor3ub(255, 255, 255);
  425. Gl.glRasterPos2i(5, 5);
  426. foreach(char c in s) {
  427. Glut.glutBitmapCharacter(Glut.GLUT_BITMAP_HELVETICA_18, c);
  428. }
  429. last = start;
  430. }
  431. Gl.glEnable(Gl.GL_LIGHTING);
  432. Gl.glEnable(Gl.GL_DEPTH_TEST);
  433. Gl.glDepthMask(Gl.GL_TRUE);
  434. Gl.glMatrixMode(Gl.GL_PROJECTION);
  435. Gl.glPopMatrix();
  436. Gl.glMatrixMode(Gl.GL_MODELVIEW);
  437. Gl.glPopMatrix();
  438. }
  439. Gl.glPushMatrix();
  440. if(texturing) {
  441. Gl.glTexGeni(Gl.GL_S, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
  442. Gl.glTexGeni(Gl.GL_T, Gl.GL_TEXTURE_GEN_MODE, Gl.GL_SPHERE_MAP);
  443. Gl.glEnable(Gl.GL_TEXTURE_GEN_S);
  444. Gl.glEnable(Gl.GL_TEXTURE_GEN_T);
  445. Gl.glEnable(Gl.GL_TEXTURE_2D);
  446. }
  447. Gl.glRotatef(spinY, 0, 1, 0);
  448. Gl.glColor3ub(196, 196, 196);
  449. Glut.glutSolidTorus(RI, RO, lod, lod);
  450. step = (int) (360.0 / numberSpheres);
  451. for(i = 0; i < numberSpheres; i++) {
  452. Gl.glPushMatrix();
  453. Gl.glRotatef(step * i + spinZ, 0, 0, 1);
  454. Gl.glTranslatef(0, RO, 0);
  455. Gl.glRotatef(step * i + spinX, 1, 0, 0);
  456. Gl.glTranslatef(0, RI + RI, 0);
  457. Color((byte) i);
  458. Sphere(i % numberTextures + 1);
  459. Gl.glPopMatrix();
  460. }
  461. if(texturing) {
  462. Gl.glDisable(Gl.GL_TEXTURE_GEN_S);
  463. Gl.glDisable(Gl.GL_TEXTURE_GEN_T);
  464. Gl.glDisable(Gl.GL_TEXTURE_2D);
  465. }
  466. Gl.glPopMatrix();
  467. Glut.glutSwapBuffers();
  468. if(performanceTiming) {
  469. end = Glut.glutGet(Glut.GLUT_ELAPSED_TIME);
  470. }
  471. }
  472. #endregion Display()
  473. #region Idle()
  474. private static void Idle() {
  475. if(!frozen) {
  476. spinY += 0.5f;
  477. if(spinY > 360) {
  478. spinY -= 360;
  479. }
  480. spinX += 10;
  481. if(spinX > 360) {
  482. spinX -= 360;
  483. }
  484. spinZ += 1;
  485. if(spinZ > 360) {
  486. spinZ -= 360;
  487. }
  488. }
  489. Glut.glutPostRedisplay();
  490. }
  491. #endregion Idle()
  492. #region Keyboard(byte key, int x, int y)
  493. private static void Keyboard(byte key, int x, int y) {
  494. switch(key) {
  495. case 27:
  496. Environment.Exit(0);
  497. break;
  498. case (byte) 'p':
  499. case (byte) 'P':
  500. performanceTiming = !performanceTiming;
  501. break;
  502. case (byte) 't':
  503. case (byte) 'T':
  504. texturing = !texturing;
  505. break;
  506. case (byte) 'm':
  507. case (byte) 'M':
  508. if(mode == Gl.GL_REPLACE) {
  509. mode = Gl.GL_MODULATE;
  510. }
  511. else {
  512. mode = Gl.GL_REPLACE;
  513. }
  514. Gl.glTexEnvi(Gl.GL_TEXTURE_ENV, Gl.GL_TEXTURE_ENV_MODE, mode);
  515. Console.WriteLine("{0} mode.", mode == Gl.GL_MODULATE ? "GL_MODULATE" : "GL_REPLACE");
  516. break;
  517. case (byte) 'f':
  518. case (byte) 'F':
  519. if(filter == Gl.GL_NEAREST) {
  520. filter = Gl.GL_LINEAR;
  521. }
  522. else {
  523. filter = Gl.GL_NEAREST;
  524. }
  525. for(int i = 0; i < numberTextures; i++) {
  526. Gl.glBindTexture(Gl.GL_TEXTURE_2D, i + 1);
  527. Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MAG_FILTER, filter);
  528. Gl.glTexParameteri(Gl.GL_TEXTURE_2D, Gl.GL_TEXTURE_MIN_FILTER, filter);
  529. }
  530. Console.WriteLine("{0} filtering.", filter == Gl.GL_LINEAR ? "GL_LINEAR" : "GL_NEAREST");
  531. break;
  532. case (byte) '>':
  533. case (byte) '.':
  534. numberTextures++;
  535. if(numberTextures > 4) {
  536. numberTextures = 4;
  537. }
  538. break;
  539. case (byte) '<':
  540. case (byte) ',':
  541. numberTextures--;
  542. if(numberTextures < 1) {
  543. numberTextures = 1;
  544. }
  545. break;
  546. case (byte) 'b':
  547. case (byte) 'B':
  548. drawBackground = !drawBackground;
  549. break;
  550. case (byte) '*':
  551. case (byte) '8':
  552. drawStars = !drawStars;
  553. break;
  554. case (byte) 'r':
  555. case (byte) 'R':
  556. Console.WriteLine("{0:F1} triangles, {1:F1} pixels.", lod * lod * 2 + (lod * 2 + lod * (lod - 2) * 2) * numberSpheres, Pixels());
  557. break;
  558. case (byte) 'c':
  559. case (byte) 'C':
  560. if(Gl.glIsEnabled(Gl.GL_CULL_FACE) == Gl.GL_TRUE) {
  561. Gl.glDisable(Gl.GL_CULL_FACE);
  562. }
  563. else {
  564. Gl.glEnable(Gl.GL_CULL_FACE);
  565. }
  566. Console.WriteLine("Culling {0}.", (Gl.glIsEnabled(Gl.GL_CULL_FACE) == Gl.GL_TRUE) ? "enabled" : "disabled");
  567. break;
  568. case (byte) ' ':
  569. frozen = !frozen;
  570. break;
  571. case (byte) '1':
  572. case (byte) '!':
  573. backgroundTexture = 1;
  574. break;
  575. case (byte) '2':
  576. case (byte) '@':
  577. backgroundTexture = 2;
  578. break;
  579. case (byte) '3':
  580. case (byte) '#':
  581. backgroundTexture = 3;
  582. break;
  583. case (byte) '4':
  584. case (byte) '$':
  585. backgroundTexture = 4;
  586. break;
  587. default:
  588. break;
  589. }
  590. }
  591. #endregion Keyboard(byte key, int x, int y)
  592. #region Menu(int value)
  593. private static void Menu(int value) {
  594. Keyboard((byte) value, 0, 0);
  595. }
  596. #endregion Menu(int value)
  597. #region Reshape(int w, int h)
  598. private static void Reshape(int w, int h) {
  599. if(h <= 0) {
  600. h = 1;
  601. }
  602. if(w <= 0) {
  603. w = 1;
  604. }
  605. width = w;
  606. height = h;
  607. Gl.glViewport(0, 0, width, height);
  608. Gl.glMatrixMode(Gl.GL_PROJECTION);
  609. Gl.glLoadIdentity();
  610. Glu.gluPerspective(120, (float) width / (float) height, 0.1, 1000.0);
  611. Gl.glMatrixMode(Gl.GL_MODELVIEW);
  612. Gl.glLoadIdentity();
  613. Glu.gluLookAt(0, 0, 20, 0, 0, 0, 0, 1, 0);
  614. for(int i = 0; i < NUMBERSTARS; i++) {
  615. stars[i].X = random.Next(RANDOMMAX) % width;
  616. stars[i].Y = random.Next(RANDOMMAX) % height;
  617. stars[i].VX = random.Next(RANDOMMAX) / (float) RANDOMMAX * 5 + 2;
  618. stars[i].VY = 0;
  619. }
  620. }
  621. #endregion Reshape(int w, int h)
  622. #region Special(int value, int x, int y)
  623. private static void Special(int value, int x, int y) {
  624. switch(value) {
  625. case Glut.GLUT_KEY_UP:
  626. lod++;
  627. if(lod > 32) {
  628. lod = 32;
  629. }
  630. break;
  631. case Glut.GLUT_KEY_DOWN:
  632. lod--;
  633. if(lod < 3) {
  634. lod = 3;
  635. }
  636. break;
  637. case Glut.GLUT_KEY_RIGHT:
  638. numberSpheres++;
  639. if(numberSpheres > COLORS) {
  640. numberSpheres = COLORS;
  641. }
  642. break;
  643. case Glut.GLUT_KEY_LEFT:
  644. numberSpheres--;
  645. if(numberSpheres < 1) {
  646. numberSpheres = 1;
  647. }
  648. break;
  649. default:
  650. break;
  651. }
  652. }
  653. #endregion Special(int value, int x, int y)
  654. }
  655. }