shapes.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933
  1. /*! \file shapes.c
  2. \ingroup demos
  3. This program is a test harness for the various shapes
  4. in OpenGLUT. It may also be useful to see which
  5. parameters control what behavior in the OpenGLUT
  6. objects.
  7. Spinning wireframe and solid-shaded shapes are
  8. displayed. Some parameters can be adjusted.
  9. Keys:
  10. - <tt>Esc &nbsp;</tt> Quit
  11. - <tt>q Q &nbsp;</tt> Quit
  12. - <tt>i I &nbsp;</tt> Show info
  13. - <tt>p P &nbsp;</tt> Toggle perspective or orthographic projection
  14. - <tt>r R &nbsp;</tt> Toggle fixed or animated rotation around model X-axis
  15. - <tt>s S &nbsp;</tt> Toggle toggle fixed function or shader render path
  16. - <tt>n N &nbsp;</tt> Toggle visualization of object's normal vectors
  17. - <tt>= + &nbsp;</tt> Increase \a slices
  18. - <tt>- _ &nbsp;</tt> Decreate \a slices
  19. - <tt>, < &nbsp;</tt> Decreate \a stacks
  20. - <tt>. > &nbsp;</tt> Increase \a stacks
  21. - <tt>9 ( &nbsp;</tt> Decreate \a depth (Sierpinski Sponge)
  22. - <tt>0 ) &nbsp;</tt> Increase \a depth (Sierpinski Sponge)
  23. - <tt>up&nbsp; &nbsp;</tt> Increase "outer radius"
  24. - <tt>down&nbsp;</tt> Decrease "outer radius"
  25. - <tt>left&nbsp;</tt> Decrease "inner radius"
  26. - <tt>right</tt> Increase "inner radius"
  27. - <tt>PgUp&nbsp;</tt> Next shape-drawing function
  28. - <tt>PgDn&nbsp;</tt> Prev shape-drawing function
  29. \author Written by Nigel Stewart November 2003
  30. \author Portions Copyright (C) 2004, the OpenGLUT project contributors. <br>
  31. OpenGLUT branched from freeglut in February, 2004.
  32. \image html openglut_shapes.png OpenGLUT Geometric Shapes Demonstration
  33. \include demos/shapes/shapes.c
  34. */
  35. #include <GL/freeglut.h>
  36. #include <stdarg.h>
  37. #include <stdio.h>
  38. #include <stdlib.h>
  39. #include <stddef.h>
  40. #include "glmatrix.h"
  41. #ifdef _MSC_VER
  42. /* DUMP MEMORY LEAKS */
  43. #include <crtdbg.h>
  44. #endif
  45. /* report GL errors, if any, to stderr */
  46. void checkError(const char *functionName)
  47. {
  48. GLenum error;
  49. while (( error = glGetError() ) != GL_NO_ERROR) {
  50. fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
  51. }
  52. }
  53. /*
  54. * OpenGL 2+ shader mode needs some function and macro definitions,
  55. * avoiding a dependency on additional libraries like GLEW or the
  56. * GL/glext.h header
  57. */
  58. #ifndef GL_FRAGMENT_SHADER
  59. #define GL_FRAGMENT_SHADER 0x8B30
  60. #endif
  61. #ifndef GL_VERTEX_SHADER
  62. #define GL_VERTEX_SHADER 0x8B31
  63. #endif
  64. #ifndef GL_COMPILE_STATUS
  65. #define GL_COMPILE_STATUS 0x8B81
  66. #endif
  67. #ifndef GL_LINK_STATUS
  68. #define GL_LINK_STATUS 0x8B82
  69. #endif
  70. #ifndef GL_INFO_LOG_LENGTH
  71. #define GL_INFO_LOG_LENGTH 0x8B84
  72. #endif
  73. typedef ptrdiff_t ourGLsizeiptr;
  74. typedef char ourGLchar;
  75. #ifndef APIENTRY
  76. #define APIENTRY
  77. #endif
  78. #ifndef GL_VERSION_2_0
  79. typedef GLuint (APIENTRY *PFNGLCREATESHADERPROC) (GLenum type);
  80. typedef void (APIENTRY *PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const ourGLchar **string, const GLint *length);
  81. typedef void (APIENTRY *PFNGLCOMPILESHADERPROC) (GLuint shader);
  82. typedef GLuint (APIENTRY *PFNGLCREATEPROGRAMPROC) (void);
  83. typedef void (APIENTRY *PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
  84. typedef void (APIENTRY *PFNGLLINKPROGRAMPROC) (GLuint program);
  85. typedef void (APIENTRY *PFNGLUSEPROGRAMPROC) (GLuint program);
  86. typedef void (APIENTRY *PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
  87. typedef void (APIENTRY *PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
  88. typedef void (APIENTRY *PFNGLGETPROGRAMIVPROC) (GLenum target, GLenum pname, GLint *params);
  89. typedef void (APIENTRY *PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
  90. typedef GLint (APIENTRY *PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const ourGLchar *name);
  91. typedef GLint (APIENTRY *PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const ourGLchar *name);
  92. typedef void (APIENTRY *PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
  93. typedef void (APIENTRY *PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
  94. #endif
  95. PFNGLCREATESHADERPROC gl_CreateShader;
  96. PFNGLSHADERSOURCEPROC gl_ShaderSource;
  97. PFNGLCOMPILESHADERPROC gl_CompileShader;
  98. PFNGLCREATEPROGRAMPROC gl_CreateProgram;
  99. PFNGLATTACHSHADERPROC gl_AttachShader;
  100. PFNGLLINKPROGRAMPROC gl_LinkProgram;
  101. PFNGLUSEPROGRAMPROC gl_UseProgram;
  102. PFNGLGETSHADERIVPROC gl_GetShaderiv;
  103. PFNGLGETSHADERINFOLOGPROC gl_GetShaderInfoLog;
  104. PFNGLGETPROGRAMIVPROC gl_GetProgramiv;
  105. PFNGLGETPROGRAMINFOLOGPROC gl_GetProgramInfoLog;
  106. PFNGLGETATTRIBLOCATIONPROC gl_GetAttribLocation;
  107. PFNGLGETUNIFORMLOCATIONPROC gl_GetUniformLocation;
  108. PFNGLUNIFORMMATRIX4FVPROC gl_UniformMatrix4fv;
  109. PFNGLUNIFORMMATRIX3FVPROC gl_UniformMatrix3fv;
  110. void initExtensionEntries(void)
  111. {
  112. gl_CreateShader = (PFNGLCREATESHADERPROC) glutGetProcAddress ("glCreateShader");
  113. gl_ShaderSource = (PFNGLSHADERSOURCEPROC) glutGetProcAddress ("glShaderSource");
  114. gl_CompileShader = (PFNGLCOMPILESHADERPROC) glutGetProcAddress ("glCompileShader");
  115. gl_CreateProgram = (PFNGLCREATEPROGRAMPROC) glutGetProcAddress ("glCreateProgram");
  116. gl_AttachShader = (PFNGLATTACHSHADERPROC) glutGetProcAddress ("glAttachShader");
  117. gl_LinkProgram = (PFNGLLINKPROGRAMPROC) glutGetProcAddress ("glLinkProgram");
  118. gl_UseProgram = (PFNGLUSEPROGRAMPROC) glutGetProcAddress ("glUseProgram");
  119. gl_GetShaderiv = (PFNGLGETSHADERIVPROC) glutGetProcAddress ("glGetShaderiv");
  120. gl_GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) glutGetProcAddress ("glGetShaderInfoLog");
  121. gl_GetProgramiv = (PFNGLGETPROGRAMIVPROC) glutGetProcAddress ("glGetProgramiv");
  122. gl_GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) glutGetProcAddress ("glGetProgramInfoLog");
  123. gl_GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glutGetProcAddress ("glGetAttribLocation");
  124. gl_GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glutGetProcAddress ("glGetUniformLocation");
  125. gl_UniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glutGetProcAddress ("glUniformMatrix4fv");
  126. gl_UniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) glutGetProcAddress ("glUniformMatrix3fv");
  127. 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_GetUniformLocation || !gl_UniformMatrix4fv || !gl_UniformMatrix3fv)
  128. {
  129. fprintf (stderr, "glCreateShader, glShaderSource, glCompileShader, glCreateProgram, glAttachShader, glLinkProgram, glUseProgram, glGetShaderiv, glGetShaderInfoLog, glGetProgramiv, glGetProgramInfoLog, glGetAttribLocation, glGetUniformLocation, glUniformMatrix4fv or gl_UniformMatrix3fv not found");
  130. exit(1);
  131. }
  132. }
  133. const ourGLchar *vertexShaderSource[] = {
  134. "/**",
  135. " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
  136. " * This file is in the public domain.",
  137. " * Contributors: Sylvain Beucler",
  138. " */",
  139. "attribute vec3 fg_coord;",
  140. "attribute vec3 fg_normal;",
  141. "varying vec4 position; /* position of the vertex (and fragment) in world space */",
  142. "varying vec3 varyingNormalDirection; /* surface normal vector in world space */",
  143. "uniform mat4 m, p; /* don't need v, as always identity in our demo */",
  144. "uniform mat3 m_3x3_inv_transp;",
  145. " ",
  146. "void main()",
  147. "{",
  148. " vec4 fg_coord4 = vec4(fg_coord, 1.0);",
  149. " position = m * fg_coord4;",
  150. " varyingNormalDirection = normalize(m_3x3_inv_transp * fg_normal);",
  151. " ",
  152. " mat4 mvp = p*m; /* normally p*v*m */",
  153. " gl_Position = mvp * fg_coord4;",
  154. "}"
  155. };
  156. const ourGLchar *fragmentShaderSource[] = {
  157. "/**",
  158. " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
  159. " * This file is in the public domain.",
  160. " * Contributors: Martin Kraus, Sylvain Beucler",
  161. " */",
  162. "varying vec4 position; /* position of the vertex (and fragment) in world space */",
  163. "varying vec3 varyingNormalDirection; /* surface normal vector in world space */",
  164. "/* uniform mat4 v_inv; // in this demo, the view matrix is always an identity matrix */",
  165. " ",
  166. "struct lightSource",
  167. "{",
  168. " vec4 position;",
  169. " vec4 diffuse;",
  170. " vec4 specular;",
  171. " float constantAttenuation, linearAttenuation, quadraticAttenuation;",
  172. " float spotCutoff, spotExponent;",
  173. " vec3 spotDirection;",
  174. "};",
  175. "lightSource light0 = lightSource(",
  176. " vec4(2.0, 5.0, 5.0, 0.0),",
  177. " vec4(1.0, 1.0, 1.0, 1.0),",
  178. " vec4(1.0, 1.0, 1.0, 1.0),",
  179. " 0.0, 1.0, 0.0,",
  180. " 180.0, 0.0,",
  181. " vec3(0.0, 0.0, 0.0)",
  182. ");",
  183. "vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);",
  184. " ",
  185. "struct material",
  186. "{",
  187. " vec4 ambient;",
  188. " vec4 diffuse;",
  189. " vec4 specular;",
  190. " float shininess;",
  191. "};",
  192. "material frontMaterial = material(",
  193. " vec4(1.0, 0.0, 0.0, 1.0),",
  194. " vec4(1.0, 0.0, 0.0, 1.0),",
  195. " vec4(1.0, 1.0, 1.0, 1.0),",
  196. " 100.0",
  197. ");",
  198. " ",
  199. "void main()",
  200. "{",
  201. " vec3 normalDirection = normalize(varyingNormalDirection);",
  202. " /* vec3 viewDirection = normalize(vec3(v_inv * vec4(0.0, 0.0, 0.0, 1.0) - position)); */",
  203. " vec3 viewDirection = normalize(vec3(vec4(0.0, 0.0, 0.0, 1.0) - position)); /* in this demo, the view matrix is always an identity matrix */",
  204. " vec3 lightDirection;",
  205. " float attenuation;",
  206. " ",
  207. " if (0.0 == light0.position.w) /* directional light? */",
  208. " {",
  209. " attenuation = 1.0; /* no attenuation */",
  210. " lightDirection = normalize(vec3(light0.position));",
  211. " } ",
  212. " else /* point light or spotlight (or other kind of light) */",
  213. " {",
  214. " vec3 positionToLightSource = vec3(light0.position - position);",
  215. " float distance = length(positionToLightSource);",
  216. " lightDirection = normalize(positionToLightSource);",
  217. " attenuation = 1.0 / (light0.constantAttenuation",
  218. " + light0.linearAttenuation * distance",
  219. " + light0.quadraticAttenuation * distance * distance);",
  220. " ",
  221. " if (light0.spotCutoff <= 90.0) /* spotlight? */",
  222. " {",
  223. " float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));",
  224. " if (clampedCosine < cos(radians(light0.spotCutoff))) /* outside of spotlight cone? */",
  225. " {",
  226. " attenuation = 0.0;",
  227. " }",
  228. " else",
  229. " {",
  230. " attenuation = attenuation * pow(clampedCosine, light0.spotExponent); ",
  231. " }",
  232. " }",
  233. " }",
  234. " ",
  235. " vec3 ambientLighting = vec3(scene_ambient) * vec3(frontMaterial.ambient);",
  236. " ",
  237. " vec3 diffuseReflection = attenuation ",
  238. " * vec3(light0.diffuse) * vec3(frontMaterial.diffuse)",
  239. " * max(0.0, dot(normalDirection, lightDirection));",
  240. " ",
  241. " vec3 specularReflection;",
  242. " if (dot(normalDirection, lightDirection) < 0.0) /* light source on the wrong side? */",
  243. " {",
  244. " specularReflection = vec3(0.0, 0.0, 0.0); /* no specular reflection */",
  245. " }",
  246. " else /* light source on the right side */",
  247. " {",
  248. " specularReflection = attenuation * vec3(light0.specular) * vec3(frontMaterial.specular) ",
  249. " * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);",
  250. " }",
  251. " ",
  252. " gl_FragColor = vec4(ambientLighting + diffuseReflection + specularReflection, 1.0);",
  253. "}"
  254. };
  255. GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isAttrib)
  256. {
  257. if (isAttrib)
  258. {
  259. GLint attrib = gl_GetAttribLocation(program, name);
  260. if (attrib == -1)
  261. {
  262. fprintf(stderr, "Warning: Could not bind attrib %s\n", name);
  263. }
  264. checkError ("getAttribOrUniformLocation");
  265. return attrib;
  266. }
  267. else
  268. {
  269. GLint uniform = gl_GetUniformLocation(program, name);
  270. if (uniform == -1)
  271. {
  272. fprintf(stderr, "Warning: Could not bind uniform %s\n", name);
  273. }
  274. checkError ("getAttribOrUniformLocation");
  275. return uniform;
  276. }
  277. }
  278. GLuint program;
  279. GLint attribute_fg_coord = -1, attribute_fg_normal = -1;
  280. GLint uniform_m = -1, uniform_p = -1, uniform_m_3x3_inv_transp = -1;
  281. GLint shaderReady = 0; /* Set to 1 when all initialization went well, to -1 when shader somehow unusable. */
  282. void compileAndCheck(GLuint shader)
  283. {
  284. GLint status;
  285. gl_CompileShader (shader);
  286. gl_GetShaderiv (shader, GL_COMPILE_STATUS, &status);
  287. if (status == GL_FALSE) {
  288. GLint infoLogLength;
  289. ourGLchar *infoLog;
  290. gl_GetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
  291. infoLog = (ourGLchar*) malloc (infoLogLength);
  292. gl_GetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
  293. fprintf (stderr, "compile log: %s\n", infoLog);
  294. free (infoLog);
  295. }
  296. checkError ("compileAndCheck");
  297. }
  298. GLuint compileShaderSource(GLenum type, GLsizei count, const ourGLchar **string)
  299. {
  300. GLuint shader = gl_CreateShader (type);
  301. gl_ShaderSource (shader, count, string, NULL);
  302. checkError ("compileShaderSource");
  303. compileAndCheck (shader);
  304. return shader;
  305. }
  306. void linkAndCheck(GLuint program)
  307. {
  308. GLint status;
  309. gl_LinkProgram (program);
  310. gl_GetProgramiv (program, GL_LINK_STATUS, &status);
  311. if (status == GL_FALSE) {
  312. GLint infoLogLength;
  313. ourGLchar *infoLog;
  314. gl_GetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLogLength);
  315. infoLog = (ourGLchar*) malloc (infoLogLength);
  316. gl_GetProgramInfoLog (program, infoLogLength, NULL, infoLog);
  317. fprintf (stderr, "link log: %s\n", infoLog);
  318. free (infoLog);
  319. }
  320. checkError ("linkAndCheck");
  321. }
  322. void createProgram(GLuint vertexShader, GLuint fragmentShader)
  323. {
  324. program = gl_CreateProgram ();
  325. if (vertexShader != 0) {
  326. gl_AttachShader (program, vertexShader);
  327. }
  328. if (fragmentShader != 0) {
  329. gl_AttachShader (program, fragmentShader);
  330. }
  331. checkError ("createProgram");
  332. linkAndCheck (program);
  333. }
  334. void initShader(void)
  335. {
  336. const GLsizei vertexShaderLines = sizeof(vertexShaderSource) / sizeof(ourGLchar*);
  337. GLuint vertexShader =
  338. compileShaderSource (GL_VERTEX_SHADER, vertexShaderLines, vertexShaderSource);
  339. const GLsizei fragmentShaderLines = sizeof(fragmentShaderSource) / sizeof(ourGLchar*);
  340. GLuint fragmentShader =
  341. compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
  342. checkError ("initShader - 1");
  343. createProgram (vertexShader, fragmentShader);
  344. gl_UseProgram (program);
  345. attribute_fg_coord = getAttribOrUniformLocation("fg_coord" , program, GL_TRUE);
  346. attribute_fg_normal = getAttribOrUniformLocation("fg_normal" , program, GL_TRUE);
  347. uniform_m = getAttribOrUniformLocation("m" , program, GL_FALSE);
  348. uniform_p = getAttribOrUniformLocation("p" , program, GL_FALSE);
  349. uniform_m_3x3_inv_transp= getAttribOrUniformLocation("m_3x3_inv_transp" , program, GL_FALSE);
  350. gl_UseProgram (0);
  351. if (attribute_fg_coord==-1 || attribute_fg_normal==-1 ||
  352. uniform_m==-1 || uniform_p==-1 || uniform_m_3x3_inv_transp==-1)
  353. shaderReady = -1;
  354. else
  355. shaderReady = 1;
  356. checkError ("initShader - 2");
  357. }
  358. /*
  359. * This macro is only intended to be used on arrays, of course.
  360. */
  361. #define NUMBEROF(x) ((sizeof(x))/(sizeof(x[0])))
  362. /*
  363. * These global variables control which object is drawn,
  364. * and how it is drawn. No object uses all of these
  365. * variables.
  366. */
  367. static int function_index;
  368. static int slices = 16;
  369. static int stacks = 16;
  370. static double irad = .25;
  371. static double orad = 1.0; /* doubles as size for objects other than Torus */
  372. static int depth = 4;
  373. static double offset[ 3 ] = { 0, 0, 0 };
  374. static GLboolean show_info = GL_TRUE;
  375. static float ar;
  376. static GLboolean persProject = GL_TRUE;
  377. static GLboolean animateXRot = GL_FALSE;
  378. static GLboolean useShader = GL_FALSE;
  379. static GLboolean visNormals = GL_FALSE;
  380. /*
  381. * Enum to tell drawSizeInfo what to draw for each object
  382. */
  383. #define GEO_NO_SIZE 0
  384. #define GEO_SIZE 1
  385. #define GEO_SCALE 2
  386. #define GEO_INNER_OUTER_RAD 4
  387. #define GEO_RAD 8
  388. #define GEO_BASE_HEIGHT 16
  389. #define GEO_RAD_HEIGHT 32
  390. /*
  391. * These one-liners draw particular objects, fetching appropriate
  392. * information from the above globals. They are just thin wrappers
  393. * for the FreeGLUT objects.
  394. */
  395. static void drawSolidTetrahedron(void) { glutSolidTetrahedron (); }
  396. static void drawWireTetrahedron(void) { glutWireTetrahedron (); }
  397. static void drawSolidCube(void) { glutSolidCube(orad); } /* orad doubles as size input */
  398. static void drawWireCube(void) { glutWireCube(orad); } /* orad doubles as size input */
  399. static void drawSolidOctahedron(void) { glutSolidOctahedron (); }
  400. static void drawWireOctahedron(void) { glutWireOctahedron (); }
  401. static void drawSolidDodecahedron(void) { glutSolidDodecahedron (); }
  402. static void drawWireDodecahedron(void) { glutWireDodecahedron (); }
  403. static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron (); }
  404. static void drawWireRhombicDodecahedron(void) { glutWireRhombicDodecahedron (); }
  405. static void drawSolidIcosahedron(void) { glutSolidIcosahedron (); }
  406. static void drawWireIcosahedron(void) { glutWireIcosahedron (); }
  407. static void drawSolidSierpinskiSponge(void) { glutSolidSierpinskiSponge (depth, offset, orad);} /* orad doubles as size input */
  408. static void drawWireSierpinskiSponge(void) { glutWireSierpinskiSponge (depth, offset, orad); } /* orad doubles as size input */
  409. static void drawSolidTorus(void) { glutSolidTorus(irad,orad,slices,stacks); }
  410. static void drawWireTorus(void) { glutWireTorus (irad,orad,slices,stacks); }
  411. static void drawSolidSphere(void) { glutSolidSphere(orad,slices,stacks); } /* orad doubles as size input */
  412. static void drawWireSphere(void) { glutWireSphere(orad,slices,stacks); } /* orad doubles as size input */
  413. static void drawSolidCone(void) { glutSolidCone(irad,orad,slices,stacks); } /* irad doubles as base input, and orad as height input */
  414. static void drawWireCone(void) { glutWireCone(irad,orad,slices,stacks); } /* irad doubles as base input, and orad as height input */
  415. static void drawSolidCylinder(void) { glutSolidCylinder(irad,orad,slices,stacks); } /* irad doubles as radius input, and orad as height input */
  416. static void drawWireCylinder(void) { glutWireCylinder(irad,orad,slices,stacks); } /* irad doubles as radius input, and orad as height input */
  417. /* per Glut manpage, it should be noted that the teapot is rendered
  418. * with clockwise winding for front facing polygons...
  419. * Same for the teacup and teaspoon
  420. */
  421. static void drawSolidTeapot(void)
  422. { glFrontFace(GL_CW); glutSolidTeapot(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  423. static void drawWireTeapot(void)
  424. { glFrontFace(GL_CW); glutWireTeapot(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  425. static void drawSolidTeacup(void)
  426. { glFrontFace(GL_CW); glutSolidTeacup(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  427. static void drawWireTeacup(void)
  428. { glFrontFace(GL_CW); glutWireTeacup(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  429. static void drawSolidTeaspoon(void)
  430. { glFrontFace(GL_CW); glutSolidTeaspoon(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  431. static void drawWireTeaspoon(void)
  432. { glFrontFace(GL_CW); glutWireTeaspoon(orad); glFrontFace(GL_CCW); /* orad doubles as size input */}
  433. #define RADIUSFAC 0.70710678118654752440084436210485f
  434. static void drawSolidCuboctahedron(void)
  435. {
  436. GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
  437. glBegin( GL_TRIANGLES );
  438. glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( 0.0, radius, radius ); glVertex3d( radius, 0.0, radius );
  439. glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( radius, 0.0,-radius ); glVertex3d( 0.0, radius,-radius );
  440. glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( 0.0,-radius, radius );
  441. glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( 0.0,-radius,-radius ); glVertex3d( radius, 0.0,-radius );
  442. glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d(-radius, 0.0, radius ); glVertex3d( 0.0, radius, radius );
  443. glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d( 0.0, radius,-radius ); glVertex3d(-radius, 0.0,-radius );
  444. glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d( 0.0,-radius, radius ); glVertex3d(-radius, 0.0, radius );
  445. glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d(-radius, 0.0,-radius ); glVertex3d( 0.0,-radius,-radius );
  446. glEnd();
  447. glBegin( GL_QUADS );
  448. glNormal3d( 1.0, 0.0, 0.0 ); glVertex3d( radius, radius, 0.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( radius,-radius, 0.0 ); glVertex3d( radius, 0.0,-radius );
  449. glNormal3d(-1.0, 0.0, 0.0 ); glVertex3d(-radius, radius, 0.0 ); glVertex3d(-radius, 0.0,-radius ); glVertex3d(-radius,-radius, 0.0 ); glVertex3d(-radius, 0.0, radius );
  450. glNormal3d( 0.0, 1.0, 0.0 ); glVertex3d( radius, radius, 0.0 ); glVertex3d( 0.0, radius,-radius ); glVertex3d(-radius, radius, 0.0 ); glVertex3d( 0.0, radius, radius );
  451. glNormal3d( 0.0,-1.0, 0.0 ); glVertex3d( radius,-radius, 0.0 ); glVertex3d( 0.0,-radius, radius ); glVertex3d(-radius,-radius, 0.0 ); glVertex3d( 0.0,-radius,-radius );
  452. glNormal3d( 0.0, 0.0, 1.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( 0.0, radius, radius ); glVertex3d(-radius, 0.0, radius ); glVertex3d( 0.0,-radius, radius );
  453. glNormal3d( 0.0, 0.0,-1.0 ); glVertex3d( radius, 0.0,-radius ); glVertex3d( 0.0,-radius,-radius ); glVertex3d(-radius, 0.0,-radius ); glVertex3d( 0.0, radius,-radius );
  454. glEnd();
  455. }
  456. static void drawWireCuboctahedron(void)
  457. {
  458. GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
  459. glBegin( GL_LINE_LOOP );
  460. glNormal3d( 1.0, 0.0, 0.0 ); glVertex3d( radius, radius, 0.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( radius,-radius, 0.0 ); glVertex3d( radius, 0.0,-radius );
  461. glEnd();
  462. glBegin( GL_LINE_LOOP );
  463. glNormal3d(-1.0, 0.0, 0.0 ); glVertex3d(-radius, radius, 0.0 ); glVertex3d(-radius, 0.0,-radius ); glVertex3d(-radius,-radius, 0.0 ); glVertex3d(-radius, 0.0, radius );
  464. glEnd();
  465. glBegin( GL_LINE_LOOP );
  466. glNormal3d( 0.0, 1.0, 0.0 ); glVertex3d( radius, radius, 0.0 ); glVertex3d( 0.0, radius,-radius ); glVertex3d(-radius, radius, 0.0 ); glVertex3d( 0.0, radius, radius );
  467. glEnd();
  468. glBegin( GL_LINE_LOOP );
  469. glNormal3d( 0.0,-1.0, 0.0 ); glVertex3d( radius,-radius, 0.0 ); glVertex3d( 0.0,-radius, radius ); glVertex3d(-radius,-radius, 0.0 ); glVertex3d( 0.0,-radius,-radius );
  470. glEnd();
  471. glBegin( GL_LINE_LOOP );
  472. glNormal3d( 0.0, 0.0, 1.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( 0.0, radius, radius ); glVertex3d(-radius, 0.0, radius ); glVertex3d( 0.0,-radius, radius );
  473. glEnd();
  474. glBegin( GL_LINE_LOOP );
  475. glNormal3d( 0.0, 0.0,-1.0 ); glVertex3d( radius, 0.0,-radius ); glVertex3d( 0.0,-radius,-radius ); glVertex3d(-radius, 0.0,-radius ); glVertex3d( 0.0, radius,-radius );
  476. glEnd();
  477. }
  478. #undef RADIUSFAC
  479. /*
  480. * This structure defines an entry in our function-table.
  481. */
  482. typedef struct
  483. {
  484. const char * const name;
  485. void (*solid) (void);
  486. void (*wire) (void);
  487. int drawSizeInfoFlag;
  488. } entry;
  489. #define ENTRY(e,f) {#e, drawSolid##e, drawWire##e,f}
  490. static const entry table [] =
  491. {
  492. ENTRY (Tetrahedron,GEO_NO_SIZE),
  493. ENTRY (Cube,GEO_SIZE),
  494. ENTRY (Octahedron,GEO_NO_SIZE),
  495. ENTRY (Dodecahedron,GEO_NO_SIZE),
  496. ENTRY (RhombicDodecahedron,GEO_NO_SIZE),
  497. ENTRY (Icosahedron,GEO_NO_SIZE),
  498. ENTRY (SierpinskiSponge,GEO_SCALE),
  499. ENTRY (Teapot,GEO_SIZE),
  500. ENTRY (Teacup,GEO_SIZE),
  501. ENTRY (Teaspoon,GEO_SIZE),
  502. ENTRY (Torus,GEO_INNER_OUTER_RAD),
  503. ENTRY (Sphere,GEO_RAD),
  504. ENTRY (Cone,GEO_BASE_HEIGHT),
  505. ENTRY (Cylinder,GEO_RAD_HEIGHT),
  506. ENTRY (Cuboctahedron,GEO_SIZE) /* This one doesn't work when in shader mode and is then skipped */
  507. };
  508. #undef ENTRY
  509. /*!
  510. Does printf()-like work using freeglut
  511. glutBitmapString(). Uses a fixed font. Prints
  512. at the indicated row/column position.
  513. Limitation: Cannot address pixels.
  514. Limitation: Renders in screen coords, not model coords.
  515. */
  516. static void shapesPrintf (int row, int col, const char *fmt, ...)
  517. {
  518. static char buf[256];
  519. int viewport[4];
  520. void *font = GLUT_BITMAP_9_BY_15;
  521. va_list args;
  522. va_start(args, fmt);
  523. #if defined(WIN32) && !defined(__CYGWIN__)
  524. (void) _vsnprintf (buf, sizeof(buf), fmt, args);
  525. #else
  526. (void) vsnprintf (buf, sizeof(buf), fmt, args);
  527. #endif
  528. va_end(args);
  529. glGetIntegerv(GL_VIEWPORT,viewport);
  530. glPushMatrix();
  531. glLoadIdentity();
  532. glMatrixMode(GL_PROJECTION);
  533. glPushMatrix();
  534. glLoadIdentity();
  535. glOrtho(0,viewport[2],0,viewport[3],-1,1);
  536. glRasterPos2i
  537. (
  538. glutBitmapWidth(font, ' ') * col,
  539. - glutBitmapHeight(font) * row + viewport[3]
  540. );
  541. glutBitmapString (font, (unsigned char*)buf);
  542. glPopMatrix();
  543. glMatrixMode(GL_MODELVIEW);
  544. glPopMatrix();
  545. }
  546. /* Print info about the about the current shape and render state on the screen */
  547. static void DrawSizeInfo(int *row)
  548. {
  549. switch (table [function_index].drawSizeInfoFlag)
  550. {
  551. case GEO_NO_SIZE:
  552. break;
  553. case GEO_SIZE:
  554. shapesPrintf ((*row)++, 1, "Size Up Down : %f", orad);
  555. break;
  556. case GEO_SCALE:
  557. shapesPrintf ((*row)++, 1, "Scale Up Down : %f", orad);
  558. break;
  559. case GEO_INNER_OUTER_RAD:
  560. shapesPrintf ((*row)++, 1, "Inner radius Left Right: %f", irad);
  561. shapesPrintf ((*row)++, 1, "Outer radius Up Down : %f", orad);
  562. break;
  563. case GEO_RAD:
  564. shapesPrintf ((*row)++, 1, "Radius Up Down : %f", orad);
  565. break;
  566. case GEO_BASE_HEIGHT:
  567. shapesPrintf ((*row)++, 1, "Base Left Right: %f", irad);
  568. shapesPrintf ((*row)++, 1, "Height Up Down : %f", orad);
  569. break;
  570. case GEO_RAD_HEIGHT:
  571. shapesPrintf ((*row)++, 1, "Radius Left Right: %f", irad);
  572. shapesPrintf ((*row)++, 1, "Height Up Down : %f", orad);
  573. break;
  574. }
  575. }
  576. static void drawInfo()
  577. {
  578. int row = 1;
  579. shapesPrintf (row++, 1, "Shape PgUp PgDn: %s", table [function_index].name);
  580. shapesPrintf (row++, 1, "Slices +-: %d Stacks <>: %d", slices, stacks);
  581. shapesPrintf (row++, 1, "nSides +-: %d nRings <>: %d", slices, stacks);
  582. shapesPrintf (row++, 1, "Depth (): %d", depth);
  583. DrawSizeInfo(&row);
  584. if (persProject)
  585. shapesPrintf (row++, 1, "Perspective projection (p)");
  586. else
  587. shapesPrintf (row++, 1, "Orthographic projection (p)");
  588. if (useShader)
  589. shapesPrintf (row++, 1, "Using shader (s)");
  590. else
  591. shapesPrintf (row++, 1, "Using fixed function pipeline (s)");
  592. if (animateXRot)
  593. shapesPrintf (row++, 1, "2D rotation (r)");
  594. else
  595. shapesPrintf (row++, 1, "1D rotation (r)");
  596. shapesPrintf (row++, 1, "visualizing normals: %i (n)",visNormals);
  597. }
  598. /* GLUT callback Handlers */
  599. static void
  600. resize(int width, int height)
  601. {
  602. ar = (float) width / (float) height;
  603. glViewport(0, 0, width, height);
  604. }
  605. static void display(void)
  606. {
  607. const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  608. const double a = t*89.0;
  609. const double b = (animateXRot?t:1)*67.0;
  610. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  611. glutSetOption(GLUT_GEOMETRY_VISUALIZE_NORMALS,visNormals); /* Normals visualized or not? */
  612. if (useShader && !shaderReady)
  613. initShader();
  614. if (useShader && shaderReady)
  615. {
  616. /* setup use of shader (and vertex buffer by FreeGLUT) */
  617. gl_UseProgram (program);
  618. glutSetVertexAttribCoord3(attribute_fg_coord);
  619. glutSetVertexAttribNormal(attribute_fg_normal);
  620. /* There is also a glutSetVertexAttribTexCoord2, which is used only when drawing the teapot, teacup or teaspoon */
  621. gl_matrix_mode(GL_PROJECTION);
  622. gl_load_identity();
  623. if (persProject)
  624. gl_frustum(-ar, ar, -1.f, 1.f, 2.f, 100.f);
  625. else
  626. gl_ortho(-ar*3, ar*3, -3.f, 3.f, 2.f, 100.f);
  627. gl_UniformMatrix4fv (uniform_p, 1, GL_FALSE, get_matrix(GL_PROJECTION));
  628. gl_matrix_mode(GL_MODELVIEW);
  629. gl_load_identity();
  630. gl_push_matrix();
  631. /* Not in reverse order like normal OpenGL, our util library multiplies the matrices in the order they are specified in */
  632. gl_rotatef((float)a,0,0,1);
  633. gl_rotatef((float)b,1,0,0);
  634. gl_translatef(0,1.2f,-6);
  635. gl_UniformMatrix4fv (uniform_m , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
  636. gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
  637. table [function_index].solid ();
  638. gl_pop_matrix();
  639. gl_push_matrix();
  640. gl_rotatef((float)a,0,0,1);
  641. gl_rotatef((float)b,1,0,0);
  642. gl_translatef(0,-1.2f,-6);
  643. gl_UniformMatrix4fv (uniform_m , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
  644. gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
  645. table [function_index].wire ();
  646. gl_pop_matrix();
  647. gl_UseProgram (0);
  648. glutSetVertexAttribCoord3(-1);
  649. glutSetVertexAttribNormal(-1);
  650. checkError ("display");
  651. }
  652. else
  653. {
  654. /* fixed function pipeline */
  655. glMatrixMode(GL_PROJECTION);
  656. glLoadIdentity();
  657. if (persProject)
  658. glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
  659. else
  660. glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
  661. glMatrixMode(GL_MODELVIEW);
  662. glLoadIdentity();
  663. glEnable(GL_LIGHTING);
  664. glColor3d(1,0,0);
  665. glPushMatrix();
  666. glTranslated(0,1.2,-6);
  667. glRotated(b,1,0,0);
  668. glRotated(a,0,0,1);
  669. table [function_index].solid ();
  670. glPopMatrix();
  671. glPushMatrix();
  672. glTranslated(0,-1.2,-6);
  673. glRotated(b,1,0,0);
  674. glRotated(a,0,0,1);
  675. table [function_index].wire ();
  676. glPopMatrix();
  677. glDisable(GL_LIGHTING);
  678. glColor3d(0.1,0.1,0.4);
  679. }
  680. if( show_info )
  681. /* print info to screen */
  682. drawInfo();
  683. else
  684. /* print to command line instead */
  685. printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
  686. glutSwapBuffers();
  687. }
  688. static void
  689. key(unsigned char key, int x, int y)
  690. {
  691. switch (key)
  692. {
  693. case 27 :
  694. case 'Q':
  695. case 'q': glutLeaveMainLoop () ; break;
  696. case 'I':
  697. case 'i': show_info=!show_info; break;
  698. case '=':
  699. case '+': slices++; break;
  700. case '-':
  701. case '_': if( slices > -1 ) slices--; break;
  702. case ',':
  703. case '<': if( stacks > -1 ) stacks--; break;
  704. case '.':
  705. case '>': stacks++; break;
  706. case '9':
  707. case '(': if( depth > -1 ) depth--; break;
  708. case '0':
  709. case ')': ++depth; break;
  710. case 'P':
  711. case 'p': persProject=!persProject; break;
  712. case 'R':
  713. case 'r': animateXRot=!animateXRot; break;
  714. case 'S':
  715. case 's':
  716. useShader=!useShader;
  717. /* Cuboctahedron can't be shown when in shader mode, move to next */
  718. if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
  719. function_index = 0;
  720. break;
  721. case 'N':
  722. case 'n': visNormals=!visNormals; break;
  723. default:
  724. break;
  725. }
  726. glutPostRedisplay();
  727. }
  728. static void special (int key, int x, int y)
  729. {
  730. switch (key)
  731. {
  732. case GLUT_KEY_PAGE_UP: ++function_index; break;
  733. case GLUT_KEY_PAGE_DOWN: --function_index; break;
  734. case GLUT_KEY_UP: orad *= 2; break;
  735. case GLUT_KEY_DOWN: orad /= 2; break;
  736. case GLUT_KEY_RIGHT: irad *= 2; break;
  737. case GLUT_KEY_LEFT: irad /= 2; break;
  738. default:
  739. break;
  740. }
  741. if (0 > function_index)
  742. function_index = NUMBEROF (table) - 1;
  743. if (NUMBEROF (table) <= ( unsigned )function_index)
  744. function_index = 0;
  745. /* Cuboctahedron can't be shown when in shader mode, skip it */
  746. if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
  747. {
  748. if (key==GLUT_KEY_PAGE_UP)
  749. function_index = 0;
  750. else
  751. function_index -= 1;
  752. }
  753. }
  754. static void
  755. idle(void)
  756. {
  757. glutPostRedisplay();
  758. }
  759. const GLfloat light_ambient[] = { 0.0f, 0.0f, 0.0f, 1.0f };
  760. const GLfloat light_diffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  761. const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  762. const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
  763. const GLfloat mat_ambient[] = { 0.7f, 0.7f, 0.7f, 1.0f };
  764. const GLfloat mat_diffuse[] = { 0.8f, 0.8f, 0.8f, 1.0f };
  765. const GLfloat mat_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
  766. const GLfloat high_shininess[] = { 100.0f };
  767. /* Program entry point */
  768. int
  769. main(int argc, char *argv[])
  770. {
  771. glutInitWindowSize(800,600);
  772. glutInitWindowPosition(40,40);
  773. glutInit(&argc, argv);
  774. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
  775. glutCreateWindow("FreeGLUT Shapes");
  776. glutReshapeFunc(resize);
  777. glutDisplayFunc(display);
  778. glutKeyboardFunc(key);
  779. glutSpecialFunc(special);
  780. glutIdleFunc(idle);
  781. glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
  782. glClearColor(1,1,1,1);
  783. glEnable(GL_CULL_FACE);
  784. glCullFace(GL_BACK);
  785. glEnable(GL_DEPTH_TEST);
  786. glDepthFunc(GL_LESS);
  787. glEnable(GL_LIGHT0);
  788. glEnable(GL_NORMALIZE);
  789. glEnable(GL_COLOR_MATERIAL);
  790. glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
  791. glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
  792. glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
  793. glLightfv(GL_LIGHT0, GL_POSITION, light_position);
  794. glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
  795. glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
  796. glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
  797. glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
  798. initExtensionEntries();
  799. glutMainLoop();
  800. #ifdef _MSC_VER
  801. /* DUMP MEMORY LEAK INFORMATION */
  802. _CrtDumpMemoryLeaks () ;
  803. #endif
  804. return EXIT_SUCCESS;
  805. }