smooth_opengl3.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469
  1. /*
  2. * smooth_opengl3.c, based on smooth.c, which is (c) by SGI, see below.
  3. * This program demonstrates smooth shading in a way which is fully
  4. * OpenGL-3.1-compliant.
  5. * A smooth shaded polygon is drawn in a 2-D projection.
  6. */
  7. /*
  8. * Original copyright notice from smooth.c:
  9. *
  10. * License Applicability. Except to the extent portions of this file are
  11. * made subject to an alternative license as permitted in the SGI Free
  12. * Software License B, Version 1.1 (the "License"), the contents of this
  13. * file are subject only to the provisions of the License. You may not use
  14. * this file except in compliance with the License. You may obtain a copy
  15. * of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
  16. * Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
  17. *
  18. * http://oss.sgi.com/projects/FreeB
  19. *
  20. * Note that, as provided in the License, the Software is distributed on an
  21. * "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
  22. * DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
  23. * CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
  24. * PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
  25. *
  26. * Original Code. The Original Code is: OpenGL Sample Implementation,
  27. * Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
  28. * Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
  29. * Copyright in any portions created by third parties is as indicated
  30. * elsewhere herein. All Rights Reserved.
  31. *
  32. * Additional Notice Provisions: The application programming interfaces
  33. * established by SGI in conjunction with the Original Code are The
  34. * OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
  35. * April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
  36. * 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
  37. * Window System(R) (Version 1.3), released October 19, 1998. This software
  38. * was created using the OpenGL(R) version 1.2.1 Sample Implementation
  39. * published by SGI, but has not been independently verified as being
  40. * compliant with the OpenGL(R) version 1.2.1 Specification.
  41. *
  42. */
  43. #include <GL/freeglut.h>
  44. #include <stdlib.h>
  45. #include <stdio.h>
  46. #include <stddef.h>
  47. #include <string.h>
  48. /* report GL errors, if any, to stderr */
  49. void checkError(const char *functionName)
  50. {
  51. GLenum error;
  52. while (( error = glGetError() ) != GL_NO_ERROR) {
  53. fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
  54. }
  55. }
  56. /* extension #defines, types and entries, avoiding a dependency on additional
  57. libraries like GLEW or the GL/glext.h header */
  58. #ifndef GL_ARRAY_BUFFER
  59. #define GL_ARRAY_BUFFER 0x8892
  60. #endif
  61. #ifndef GL_STATIC_DRAW
  62. #define GL_STATIC_DRAW 0x88E4
  63. #endif
  64. #ifndef GL_FRAGMENT_SHADER
  65. #define GL_FRAGMENT_SHADER 0x8B30
  66. #endif
  67. #ifndef GL_VERTEX_SHADER
  68. #define GL_VERTEX_SHADER 0x8B31
  69. #endif
  70. #ifndef GL_SHADING_LANGUAGE_VERSION
  71. #define GL_SHADING_LANGUAGE_VERSION 0x8B8C
  72. #endif
  73. #ifndef GL_COMPILE_STATUS
  74. #define GL_COMPILE_STATUS 0x8B81
  75. #endif
  76. #ifndef GL_LINK_STATUS
  77. #define GL_LINK_STATUS 0x8B82
  78. #endif
  79. #ifndef GL_INFO_LOG_LENGTH
  80. #define GL_INFO_LOG_LENGTH 0x8B84
  81. #endif
  82. typedef ptrdiff_t ourGLsizeiptr;
  83. typedef char ourGLchar;
  84. #ifndef APIENTRY
  85. #define APIENTRY
  86. #endif
  87. #ifndef GL_ARB_vertex_array_object
  88. typedef void (APIENTRY *PFNGLGENVERTEXARRAYSPROC) (GLsizei n, GLuint *arrays);
  89. typedef void (APIENTRY *PFNGLBINDVERTEXARRAYPROC) (GLuint array);
  90. #endif
  91. #ifndef GL_VERSION_1_5
  92. typedef void (APIENTRY *PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
  93. typedef void (APIENTRY *PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
  94. typedef void (APIENTRY *PFNGLBUFFERDATAPROC) (GLenum target, ourGLsizeiptr size, const GLvoid *data, GLenum usage);
  95. #endif
  96. #ifndef GL_VERSION_2_0
  97. typedef GLuint (APIENTRY *PFNGLCREATESHADERPROC) (GLenum type);
  98. typedef void (APIENTRY *PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const ourGLchar **string, const GLint *length);
  99. typedef void (APIENTRY *PFNGLCOMPILESHADERPROC) (GLuint shader);
  100. typedef GLuint (APIENTRY *PFNGLCREATEPROGRAMPROC) (void);
  101. typedef void (APIENTRY *PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
  102. typedef void (APIENTRY *PFNGLLINKPROGRAMPROC) (GLuint program);
  103. typedef void (APIENTRY *PFNGLUSEPROGRAMPROC) (GLuint program);
  104. typedef void (APIENTRY *PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
  105. typedef void (APIENTRY *PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
  106. typedef void (APIENTRY *PFNGLGETPROGRAMIVPROC) (GLenum target, GLenum pname, GLint *params);
  107. typedef void (APIENTRY *PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
  108. typedef GLint (APIENTRY *PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const ourGLchar *name);
  109. typedef void (APIENTRY *PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *pointer);
  110. typedef void (APIENTRY *PFNGLENABLEVERTEXATTRIBARRAYPROC) (GLuint index);
  111. typedef GLint (APIENTRY *PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const ourGLchar *name);
  112. typedef void (APIENTRY *PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
  113. #endif
  114. PFNGLGENVERTEXARRAYSPROC gl_GenVertexArrays;
  115. PFNGLBINDVERTEXARRAYPROC gl_BindVertexArray;
  116. PFNGLGENBUFFERSPROC gl_GenBuffers;
  117. PFNGLBINDBUFFERPROC gl_BindBuffer;
  118. PFNGLBUFFERDATAPROC gl_BufferData;
  119. PFNGLCREATESHADERPROC gl_CreateShader;
  120. PFNGLSHADERSOURCEPROC gl_ShaderSource;
  121. PFNGLCOMPILESHADERPROC gl_CompileShader;
  122. PFNGLCREATEPROGRAMPROC gl_CreateProgram;
  123. PFNGLATTACHSHADERPROC gl_AttachShader;
  124. PFNGLLINKPROGRAMPROC gl_LinkProgram;
  125. PFNGLUSEPROGRAMPROC gl_UseProgram;
  126. PFNGLGETSHADERIVPROC gl_GetShaderiv;
  127. PFNGLGETSHADERINFOLOGPROC gl_GetShaderInfoLog;
  128. PFNGLGETPROGRAMIVPROC gl_GetProgramiv;
  129. PFNGLGETPROGRAMINFOLOGPROC gl_GetProgramInfoLog;
  130. PFNGLGETATTRIBLOCATIONPROC gl_GetAttribLocation;
  131. PFNGLVERTEXATTRIBPOINTERPROC gl_VertexAttribPointer;
  132. PFNGLENABLEVERTEXATTRIBARRAYPROC gl_EnableVertexAttribArray;
  133. PFNGLGETUNIFORMLOCATIONPROC gl_GetUniformLocation;
  134. PFNGLUNIFORMMATRIX4FVPROC gl_UniformMatrix4fv;
  135. void initExtensionEntries(void)
  136. {
  137. gl_GenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) glutGetProcAddress ("glGenVertexArrays");
  138. gl_BindVertexArray = (PFNGLBINDVERTEXARRAYPROC) glutGetProcAddress ("glBindVertexArray");
  139. if (!gl_GenVertexArrays || !gl_BindVertexArray)
  140. {
  141. fprintf (stderr, "glGenVertexArrays or glBindVertexArray not found");
  142. exit(1);
  143. }
  144. gl_GenBuffers = (PFNGLGENBUFFERSPROC) glutGetProcAddress ("glGenBuffers");
  145. gl_BindBuffer = (PFNGLBINDBUFFERPROC) glutGetProcAddress ("glBindBuffer");
  146. gl_BufferData = (PFNGLBUFFERDATAPROC) glutGetProcAddress ("glBufferData");
  147. if (!gl_GenBuffers || !gl_BindBuffer || !gl_BufferData)
  148. {
  149. fprintf (stderr, "glGenBuffers, glBindBuffer or glBufferData not found");
  150. exit(1);
  151. }
  152. gl_CreateShader = (PFNGLCREATESHADERPROC) glutGetProcAddress ("glCreateShader");
  153. gl_ShaderSource = (PFNGLSHADERSOURCEPROC) glutGetProcAddress ("glShaderSource");
  154. gl_CompileShader = (PFNGLCOMPILESHADERPROC) glutGetProcAddress ("glCompileShader");
  155. gl_CreateProgram = (PFNGLCREATEPROGRAMPROC) glutGetProcAddress ("glCreateProgram");
  156. gl_AttachShader = (PFNGLATTACHSHADERPROC) glutGetProcAddress ("glAttachShader");
  157. gl_LinkProgram = (PFNGLLINKPROGRAMPROC) glutGetProcAddress ("glLinkProgram");
  158. gl_UseProgram = (PFNGLUSEPROGRAMPROC) glutGetProcAddress ("glUseProgram");
  159. gl_GetShaderiv = (PFNGLGETSHADERIVPROC) glutGetProcAddress ("glGetShaderiv");
  160. gl_GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) glutGetProcAddress ("glGetShaderInfoLog");
  161. gl_GetProgramiv = (PFNGLGETPROGRAMIVPROC) glutGetProcAddress ("glGetProgramiv");
  162. gl_GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) glutGetProcAddress ("glGetProgramInfoLog");
  163. gl_GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glutGetProcAddress ("glGetAttribLocation");
  164. gl_VertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) glutGetProcAddress ("glVertexAttribPointer");
  165. gl_EnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) glutGetProcAddress ("glEnableVertexAttribArray");
  166. gl_GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glutGetProcAddress ("glGetUniformLocation");
  167. gl_UniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glutGetProcAddress ("glUniformMatrix4fv");
  168. if (!gl_CreateShader || !gl_ShaderSource || !gl_CompileShader || !gl_CreateProgram || !gl_AttachShader || !gl_LinkProgram || !gl_UseProgram || !gl_GetShaderiv || !gl_GetShaderInfoLog || !gl_GetProgramiv || !gl_GetProgramInfoLog || !gl_GetAttribLocation || !gl_VertexAttribPointer || !gl_EnableVertexAttribArray || !gl_GetUniformLocation || !gl_UniformMatrix4fv)
  169. {
  170. fprintf (stderr, "glCreateShader, glShaderSource, glCompileShader, glCreateProgram, glAttachShader, glLinkProgram, glUseProgram, glGetShaderiv, glGetShaderInfoLog, glGetProgramiv, glGetProgramInfoLog, glGetAttribLocation, glVertexAttribPointer, glEnableVertexAttribArray, glGetUniformLocation or glUniformMatrix4fv not found");
  171. exit(1);
  172. }
  173. }
  174. /* vertex array data for a colored 2D triangle, consisting of RGB color values
  175. and XY coordinates */
  176. const GLfloat varray[] = {
  177. 1.0f, 0.0f, 0.0f, /* red */
  178. 5.0f, 5.0f, /* lower left */
  179. 0.0f, 1.0f, 0.0f, /* green */
  180. 25.0f, 5.0f, /* lower right */
  181. 0.0f, 0.0f, 1.0f, /* blue */
  182. 5.0f, 25.0f /* upper left */
  183. };
  184. /* ISO C somehow enforces this silly use of 'enum' for compile-time constants */
  185. enum {
  186. numColorComponents = 3,
  187. numVertexComponents = 2,
  188. stride = sizeof(GLfloat) * (numColorComponents + numVertexComponents),
  189. numElements = sizeof(varray) / stride
  190. };
  191. /* the name of the vertex buffer object */
  192. GLuint vertexBufferName;
  193. GLuint vertexArrayName;
  194. void initBuffer(void)
  195. {
  196. /* Need to setup a vertex array as otherwise invalid operation errors can
  197. * occur when accessing vertex buffer (OpenGL 3.3 has no default zero named
  198. * vertex array)
  199. */
  200. gl_GenVertexArrays(1, &vertexArrayName);
  201. gl_BindVertexArray(vertexArrayName);
  202. gl_GenBuffers (1, &vertexBufferName);
  203. gl_BindBuffer (GL_ARRAY_BUFFER, vertexBufferName);
  204. gl_BufferData (GL_ARRAY_BUFFER, sizeof(varray), varray, GL_STATIC_DRAW);
  205. checkError ("initBuffer");
  206. }
  207. const ourGLchar *vertexShaderSource[] = {
  208. "#version 140\n",
  209. "uniform mat4 fg_ProjectionMatrix;\n",
  210. "in vec4 fg_Color;\n",
  211. "in vec4 fg_Vertex;\n",
  212. "smooth out vec4 fg_SmoothColor;\n",
  213. "void main()\n",
  214. "{\n",
  215. " fg_SmoothColor = fg_Color;\n",
  216. " gl_Position = fg_ProjectionMatrix * fg_Vertex;\n",
  217. "}\n"
  218. };
  219. const ourGLchar *fragmentShaderSource[] = {
  220. "#version 140\n",
  221. "smooth in vec4 fg_SmoothColor;\n",
  222. "out vec4 fg_FragColor;\n",
  223. "void main(void)\n",
  224. "{\n",
  225. " fg_FragColor = fg_SmoothColor;\n",
  226. "}\n"
  227. };
  228. void compileAndCheck(GLuint shader)
  229. {
  230. GLint status;
  231. gl_CompileShader (shader);
  232. gl_GetShaderiv (shader, GL_COMPILE_STATUS, &status);
  233. if (status == GL_FALSE) {
  234. GLint infoLogLength;
  235. ourGLchar *infoLog;
  236. gl_GetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
  237. infoLog = (ourGLchar*) malloc (infoLogLength);
  238. gl_GetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
  239. fprintf (stderr, "compile log: %s\n", infoLog);
  240. free (infoLog);
  241. }
  242. }
  243. GLuint compileShaderSource(GLenum type, GLsizei count, const ourGLchar **string)
  244. {
  245. GLuint shader = gl_CreateShader (type);
  246. gl_ShaderSource (shader, count, string, NULL);
  247. compileAndCheck (shader);
  248. return shader;
  249. }
  250. void linkAndCheck(GLuint program)
  251. {
  252. GLint status;
  253. gl_LinkProgram (program);
  254. gl_GetProgramiv (program, GL_LINK_STATUS, &status);
  255. if (status == GL_FALSE) {
  256. GLint infoLogLength;
  257. ourGLchar *infoLog;
  258. gl_GetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLogLength);
  259. infoLog = (ourGLchar*) malloc (infoLogLength);
  260. gl_GetProgramInfoLog (program, infoLogLength, NULL, infoLog);
  261. fprintf (stderr, "link log: %s\n", infoLog);
  262. free (infoLog);
  263. }
  264. }
  265. GLuint createProgram(GLuint vertexShader, GLuint fragmentShader)
  266. {
  267. GLuint program = gl_CreateProgram ();
  268. if (vertexShader != 0) {
  269. gl_AttachShader (program, vertexShader);
  270. }
  271. if (fragmentShader != 0) {
  272. gl_AttachShader (program, fragmentShader);
  273. }
  274. linkAndCheck (program);
  275. return program;
  276. }
  277. GLuint fgProjectionMatrixIndex;
  278. GLuint fgColorIndex;
  279. GLuint fgVertexIndex;
  280. void initShader(void)
  281. {
  282. const GLsizei vertexShaderLines = sizeof(vertexShaderSource) / sizeof(ourGLchar*);
  283. GLuint vertexShader =
  284. compileShaderSource (GL_VERTEX_SHADER, vertexShaderLines, vertexShaderSource);
  285. const GLsizei fragmentShaderLines = sizeof(fragmentShaderSource) / sizeof(ourGLchar*);
  286. GLuint fragmentShader =
  287. compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
  288. GLuint program = createProgram (vertexShader, fragmentShader);
  289. gl_UseProgram (program);
  290. fgProjectionMatrixIndex = gl_GetUniformLocation(program, "fg_ProjectionMatrix");
  291. fgColorIndex = gl_GetAttribLocation(program, "fg_Color");
  292. gl_EnableVertexAttribArray (fgColorIndex);
  293. fgVertexIndex = gl_GetAttribLocation(program, "fg_Vertex");
  294. gl_EnableVertexAttribArray (fgVertexIndex);
  295. checkError ("initShader");
  296. }
  297. void initRendering(void)
  298. {
  299. glClearColor (0.0, 0.0, 0.0, 0.0);
  300. checkError ("initRendering");
  301. }
  302. void init(void)
  303. {
  304. initExtensionEntries ();
  305. initBuffer ();
  306. initShader ();
  307. initRendering ();
  308. }
  309. void dumpInfo(void)
  310. {
  311. printf ("Vendor: %s\n", glGetString (GL_VENDOR));
  312. printf ("Renderer: %s\n", glGetString (GL_RENDERER));
  313. printf ("Version: %s\n", glGetString (GL_VERSION));
  314. printf ("GLSL: %s\n", glGetString (GL_SHADING_LANGUAGE_VERSION));
  315. checkError ("dumpInfo");
  316. }
  317. const GLvoid *bufferObjectPtr (GLsizei index)
  318. {
  319. return (const GLvoid *) (((char *) NULL) + index);
  320. }
  321. GLfloat projectionMatrix[16];
  322. void triangle(void)
  323. {
  324. gl_UniformMatrix4fv (fgProjectionMatrixIndex, 1, GL_FALSE, projectionMatrix);
  325. gl_BindBuffer (GL_ARRAY_BUFFER, vertexBufferName);
  326. gl_VertexAttribPointer (fgColorIndex, numColorComponents, GL_FLOAT, GL_FALSE,
  327. stride, bufferObjectPtr (0));
  328. gl_VertexAttribPointer (fgVertexIndex, numVertexComponents, GL_FLOAT, GL_FALSE,
  329. stride, bufferObjectPtr (sizeof(GLfloat) * numColorComponents));
  330. glDrawArrays(GL_TRIANGLES, 0, numElements);
  331. checkError ("triangle");
  332. }
  333. void display(void)
  334. {
  335. glClear (GL_COLOR_BUFFER_BIT);
  336. triangle ();
  337. glFlush ();
  338. checkError ("display");
  339. }
  340. void loadOrthof(GLfloat *m, GLfloat l, GLfloat r, GLfloat b, GLfloat t,
  341. GLfloat n, GLfloat f)
  342. {
  343. m[ 0] = 2.0f / (r - l);
  344. m[ 1] = 0.0f;
  345. m[ 2] = 0.0f;
  346. m[ 3] = 0.0f;
  347. m[ 4] = 0.0f;
  348. m[ 5] = 2.0f / (t - b);
  349. m[ 6] = 0.0f;
  350. m[ 7] = 0.0f;
  351. m[ 8] = 0.0f;
  352. m[ 9] = 0.0f;
  353. m[10] = -2.0f / (f - n);
  354. m[11] = 0.0f;
  355. m[12] = -(r + l) / (r - l);
  356. m[13] = -(t + b) / (t - b);
  357. m[14] = -(f + n) / (f - n);
  358. m[15] = 1.0f;
  359. }
  360. void loadOrtho2Df(GLfloat *m, GLfloat l, GLfloat r, GLfloat b, GLfloat t)
  361. {
  362. loadOrthof (m, l, r, b, t, -1.0f, 1.0f);
  363. }
  364. void reshape (int w, int h)
  365. {
  366. glViewport (0, 0, (GLsizei) w, (GLsizei) h);
  367. if (w <= h) {
  368. loadOrtho2Df (projectionMatrix, 0.0f, 30.0f, 0.0f, 30.0f * (GLfloat) h/(GLfloat) w);
  369. } else {
  370. loadOrtho2Df (projectionMatrix, 0.0f, 30.0f * (GLfloat) w/(GLfloat) h, 0.0f, 30.0f);
  371. }
  372. checkError ("reshape");
  373. }
  374. void keyboard(unsigned char key, int x, int y)
  375. {
  376. switch (key) {
  377. case 27:
  378. exit(0);
  379. break;
  380. }
  381. }
  382. void samplemenu(int menuID)
  383. {}
  384. int main(int argc, char** argv)
  385. {
  386. int menuA;
  387. glutInit(&argc, argv);
  388. glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
  389. /* add command line argument "classic" for a pre-3.x context */
  390. if ((argc != 2) || (strcmp (argv[1], "classic") != 0)) {
  391. glutInitContextVersion (3, 1);
  392. glutInitContextFlags (GLUT_FORWARD_COMPATIBLE | GLUT_DEBUG);
  393. }
  394. glutInitWindowSize (500, 500);
  395. glutInitWindowPosition (100, 100);
  396. glutCreateWindow (argv[0]);
  397. dumpInfo ();
  398. init ();
  399. glutDisplayFunc(display);
  400. glutReshapeFunc(reshape);
  401. glutKeyboardFunc (keyboard);
  402. /* Add a menu. They have their own context and should thus work with forward compatible main windows too. */
  403. menuA = glutCreateMenu(samplemenu);
  404. glutAddMenuEntry("Sub menu A1 (01)",1);
  405. glutAddMenuEntry("Sub menu A2 (02)",2);
  406. glutAddMenuEntry("Sub menu A3 (03)",3);
  407. glutSetMenu(menuA);
  408. glutAttachMenu(GLUT_RIGHT_BUTTON);
  409. glutMainLoop();
  410. return 0;
  411. }