Clone of mesa.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /* $Id: shadowtex.c,v 1.4 2001/02/28 18:41:50 brianp Exp $ */
  2. /*
  3. * Shadow demo using the GL_SGIX_depth_texture, GL_SGIX_shadow and
  4. * GL_SGIX_shadow_ambient extensions.
  5. *
  6. * Brian Paul
  7. * 19 Feb 2001
  8. *
  9. * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
  10. *
  11. * Permission is hereby granted, free of charge, to any person obtaining a
  12. * copy of this software and associated documentation files (the "Software"),
  13. * to deal in the Software without restriction, including without limitation
  14. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  15. * and/or sell copies of the Software, and to permit persons to whom the
  16. * Software is furnished to do so, subject to the following conditions:
  17. *
  18. * The above copyright notice and this permission notice shall be included
  19. * in all copies or substantial portions of the Software.
  20. *
  21. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  22. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  24. * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  25. * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  26. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. #include <assert.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include <math.h>
  32. #include <GL/glut.h>
  33. #include "../util/showbuffer.c"
  34. #define DEG_TO_RAD (3.14159 / 180.0)
  35. static GLint WindowWidth = 450, WindowHeight = 300;
  36. static GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
  37. static GLfloat Red[4] = {1, 0, 0, 1};
  38. static GLfloat Green[4] = {0, 1, 0, 1};
  39. static GLfloat Blue[4] = {0, 0, 1, 1};
  40. static GLfloat Yellow[4] = {1, 1, 0, 1};
  41. static GLfloat LightDist = 10;
  42. static GLfloat LightLatitude = 45.0;
  43. static GLfloat LightLongitude = 45.0;
  44. static GLfloat LightPos[4];
  45. static GLfloat SpotDir[3];
  46. static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
  47. static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
  48. static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
  49. static GLboolean LinearFilter = GL_FALSE;
  50. static GLfloat Bias = -0.06;
  51. static GLboolean Anim = GL_TRUE;
  52. static GLuint DisplayMode;
  53. #define SHOW_NORMAL 0
  54. #define SHOW_DEPTH_IMAGE 1
  55. #define SHOW_DEPTH_MAPPING 2
  56. #define SHOW_DISTANCE 3
  57. static void
  58. DrawScene(void)
  59. {
  60. GLfloat k = 6;
  61. /* sphere */
  62. glPushMatrix();
  63. glTranslatef(1.6, 2.2, 2.7);
  64. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
  65. glColor4fv(Green);
  66. glutSolidSphere(1.5, 15, 15);
  67. glPopMatrix();
  68. /* dodecahedron */
  69. glPushMatrix();
  70. glTranslatef(-2.0, 1.2, 2.1);
  71. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
  72. glColor4fv(Red);
  73. glutSolidDodecahedron();
  74. glPopMatrix();
  75. /* icosahedron */
  76. glPushMatrix();
  77. glTranslatef(-0.6, 1.3, -0.5);
  78. glScalef(1.5, 1.5, 1.5);
  79. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
  80. glColor4fv(Red);
  81. glutSolidIcosahedron();
  82. glPopMatrix();
  83. /* a plane */
  84. glPushMatrix();
  85. glTranslatef(0, -1.1, 0);
  86. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
  87. glColor4fv(Blue);
  88. glNormal3f(0, 1, 0);
  89. glBegin(GL_POLYGON);
  90. glVertex3f(-k, 0, -k);
  91. glVertex3f( k, 0, -k);
  92. glVertex3f( k, 0, k);
  93. glVertex3f(-k, 0, k);
  94. glEnd();
  95. glPopMatrix();
  96. }
  97. /*
  98. * Load the GL_TEXTURE matrix with the projection from the light
  99. * source's point of view.
  100. */
  101. static void
  102. MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
  103. GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
  104. {
  105. GLfloat d;
  106. glMatrixMode(GL_TEXTURE);
  107. glLoadIdentity();
  108. glTranslatef(0.5, 0.5, 0.5 + Bias);
  109. glScalef(0.5, 0.5, 0.5);
  110. d = shadowNear * tan(spotAngle);
  111. glFrustum(-d, d, -d, d, shadowNear, shadowFar);
  112. gluLookAt(lightPos[0], lightPos[1], lightPos[2],
  113. lightPos[0] + spotDir[0],
  114. lightPos[1] + spotDir[1],
  115. lightPos[2] + spotDir[2],
  116. 0, 1, 0);
  117. glMatrixMode(GL_MODELVIEW);
  118. }
  119. static void
  120. EnableIdentityTexgen(void)
  121. {
  122. /* texgen so that texcoord = vertex coord */
  123. static GLfloat sPlane[4] = { 1, 0, 0, 0 };
  124. static GLfloat tPlane[4] = { 0, 1, 0, 0 };
  125. static GLfloat rPlane[4] = { 0, 0, 1, 0 };
  126. static GLfloat qPlane[4] = { 0, 0, 0, 1 };
  127. glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
  128. glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
  129. glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
  130. glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
  131. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  132. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  133. glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  134. glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  135. glEnable(GL_TEXTURE_GEN_S);
  136. glEnable(GL_TEXTURE_GEN_T);
  137. glEnable(GL_TEXTURE_GEN_R);
  138. glEnable(GL_TEXTURE_GEN_Q);
  139. }
  140. /*
  141. * Setup 1-D texgen so that the distance from the light source, between
  142. * the near and far planes maps to s=0 and s=1. When we draw the scene,
  143. * the grayness will indicate the fragment's distance from the light
  144. * source.
  145. */
  146. static void
  147. EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
  148. GLfloat lightNear, GLfloat lightFar)
  149. {
  150. GLfloat m, d;
  151. GLfloat sPlane[4];
  152. GLfloat nearPoint[3];
  153. m = sqrt(lightDir[0] * lightDir[0] +
  154. lightDir[1] * lightDir[1] +
  155. lightDir[2] * lightDir[2]);
  156. d = lightFar - lightNear;
  157. /* nearPoint = point on light direction vector which intersects the
  158. * near plane of the light frustum.
  159. */
  160. nearPoint[0] = LightPos[0] + lightDir[0] / m * lightNear;
  161. nearPoint[1] = LightPos[1] + lightDir[1] / m * lightNear;
  162. nearPoint[2] = LightPos[2] + lightDir[2] / m * lightNear;
  163. sPlane[0] = lightDir[0] / d / m;
  164. sPlane[1] = lightDir[1] / d / m;
  165. sPlane[2] = lightDir[2] / d / m;
  166. sPlane[3] = -(sPlane[0] * nearPoint[0]
  167. + sPlane[1] * nearPoint[1]
  168. + sPlane[2] * nearPoint[2]);
  169. glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
  170. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  171. glEnable(GL_TEXTURE_GEN_S);
  172. }
  173. static void
  174. DisableTexgen(void)
  175. {
  176. glDisable(GL_TEXTURE_GEN_S);
  177. glDisable(GL_TEXTURE_GEN_T);
  178. glDisable(GL_TEXTURE_GEN_R);
  179. glDisable(GL_TEXTURE_GEN_Q);
  180. }
  181. static void
  182. ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
  183. GLfloat pos[4], GLfloat dir[3])
  184. {
  185. pos[0] = dist * sin(longitude * DEG_TO_RAD);
  186. pos[1] = dist * sin(latitude * DEG_TO_RAD);
  187. pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
  188. pos[3] = 1;
  189. dir[0] = -pos[0];
  190. dir[1] = -pos[1];
  191. dir[2] = -pos[2];
  192. }
  193. static void
  194. Display(void)
  195. {
  196. GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
  197. GLfloat d;
  198. ComputeLightPos(LightDist, LightLatitude, LightLongitude,
  199. LightPos, SpotDir);
  200. /*
  201. * Step 1: render scene from point of view of the light source
  202. */
  203. /* compute frustum to enclose spot light cone */
  204. d = ShadowNear * tan(SpotAngle);
  205. glMatrixMode(GL_PROJECTION);
  206. glLoadIdentity();
  207. glFrustum(-d, d, -d, d, ShadowNear, ShadowFar);
  208. glMatrixMode(GL_MODELVIEW);
  209. glLoadIdentity();
  210. gluLookAt(LightPos[0], LightPos[1], LightPos[2], /* from */
  211. 0, 0, 0, /* target */
  212. 0, 1, 0); /* up */
  213. glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
  214. glClear(GL_DEPTH_BUFFER_BIT);
  215. DrawScene();
  216. /*
  217. * Step 2: copy depth buffer into texture map
  218. */
  219. if (DisplayMode == SHOW_DEPTH_MAPPING) {
  220. /* load depth image as gray-scale luminance texture */
  221. GLfloat *depth = malloc(ShadowTexWidth * ShadowTexHeight
  222. * sizeof(GLfloat));
  223. if (depth) {
  224. glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
  225. GL_DEPTH_COMPONENT, GL_FLOAT, depth);
  226. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
  227. ShadowTexWidth, ShadowTexHeight, 0,
  228. GL_LUMINANCE, GL_FLOAT, depth);
  229. free(depth);
  230. }
  231. }
  232. else {
  233. /* The normal shadow case */
  234. glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT,
  235. 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
  236. }
  237. /*
  238. * Step 3: render scene from point of view of the camera
  239. */
  240. glViewport(0, 0, WindowWidth, WindowHeight);
  241. if (DisplayMode == SHOW_DEPTH_IMAGE) {
  242. ShowDepthBuffer(WindowWidth, WindowHeight, 0, 1);
  243. }
  244. else {
  245. glMatrixMode(GL_PROJECTION);
  246. glLoadIdentity();
  247. glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
  248. glMatrixMode(GL_MODELVIEW);
  249. glLoadIdentity();
  250. glTranslatef(0.0, 0.0, -22.0);
  251. glRotatef(Xrot, 1, 0, 0);
  252. glRotatef(Yrot, 0, 1, 0);
  253. glRotatef(Zrot, 0, 0, 1);
  254. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  255. glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
  256. if (LinearFilter) {
  257. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  258. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  259. }
  260. else {
  261. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  262. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  263. }
  264. if (DisplayMode == SHOW_DEPTH_MAPPING) {
  265. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_FALSE);
  266. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  267. glEnable(GL_TEXTURE_2D);
  268. MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
  269. EnableIdentityTexgen();
  270. }
  271. else if (DisplayMode == SHOW_DISTANCE) {
  272. glMatrixMode(GL_TEXTURE);
  273. glLoadIdentity();
  274. glMatrixMode(GL_MODELVIEW);
  275. EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
  276. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  277. glEnable(GL_TEXTURE_1D);
  278. }
  279. else {
  280. assert(DisplayMode == SHOW_NORMAL);
  281. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_SGIX, GL_TRUE);
  282. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  283. glEnable(GL_TEXTURE_2D);
  284. MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
  285. EnableIdentityTexgen();
  286. }
  287. DrawScene();
  288. DisableTexgen();
  289. glDisable(GL_TEXTURE_1D);
  290. glDisable(GL_TEXTURE_2D);
  291. }
  292. glutSwapBuffers();
  293. }
  294. static void
  295. Reshape(int width, int height)
  296. {
  297. WindowWidth = width;
  298. WindowHeight = height;
  299. if (width >= 512 && height >= 512) {
  300. ShadowTexWidth = ShadowTexHeight = 512;
  301. }
  302. else if (width >= 256 && height >= 256) {
  303. ShadowTexWidth = ShadowTexHeight = 256;
  304. }
  305. else {
  306. ShadowTexWidth = ShadowTexHeight = 128;
  307. }
  308. printf("Using %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
  309. }
  310. static void
  311. Idle(void)
  312. {
  313. Yrot += 5.0;
  314. /*LightLongitude -= 5.0;*/
  315. glutPostRedisplay();
  316. }
  317. static void
  318. Key(unsigned char key, int x, int y)
  319. {
  320. const GLfloat step = 3.0;
  321. (void) x;
  322. (void) y;
  323. switch (key) {
  324. case 'a':
  325. Anim = !Anim;
  326. if (Anim)
  327. glutIdleFunc(Idle);
  328. else
  329. glutIdleFunc(NULL);
  330. break;
  331. case 'b':
  332. Bias -= 0.01;
  333. printf("Bias %g\n", Bias);
  334. break;
  335. case 'B':
  336. Bias += 0.01;
  337. printf("Bias %g\n", Bias);
  338. break;
  339. case 'd':
  340. DisplayMode = SHOW_DISTANCE;
  341. break;
  342. case 'f':
  343. LinearFilter = !LinearFilter;
  344. printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
  345. break;
  346. case 'i':
  347. DisplayMode = SHOW_DEPTH_IMAGE;
  348. break;
  349. case 'm':
  350. DisplayMode = SHOW_DEPTH_MAPPING;
  351. break;
  352. case 'n':
  353. case ' ':
  354. DisplayMode = SHOW_NORMAL;
  355. break;
  356. case 'z':
  357. Zrot -= step;
  358. break;
  359. case 'Z':
  360. Zrot += step;
  361. break;
  362. case 27:
  363. exit(0);
  364. break;
  365. }
  366. glutPostRedisplay();
  367. }
  368. static void
  369. SpecialKey(int key, int x, int y)
  370. {
  371. const GLfloat step = 3.0;
  372. const int mod = glutGetModifiers();
  373. (void) x;
  374. (void) y;
  375. switch (key) {
  376. case GLUT_KEY_UP:
  377. if (mod)
  378. LightLatitude += step;
  379. else
  380. Xrot += step;
  381. break;
  382. case GLUT_KEY_DOWN:
  383. if (mod)
  384. LightLatitude -= step;
  385. else
  386. Xrot -= step;
  387. break;
  388. case GLUT_KEY_LEFT:
  389. if (mod)
  390. LightLongitude += step;
  391. else
  392. Yrot += step;
  393. break;
  394. case GLUT_KEY_RIGHT:
  395. if (mod)
  396. LightLongitude -= step;
  397. else
  398. Yrot -= step;
  399. break;
  400. }
  401. glutPostRedisplay();
  402. }
  403. static void
  404. Init(void)
  405. {
  406. if (!glutExtensionSupported("GL_SGIX_depth_texture") ||
  407. !glutExtensionSupported("GL_SGIX_shadow")) {
  408. printf("Sorry, this demo requires the GL_SGIX_depth_texture and GL_SGIX_shadow extensions\n");
  409. exit(1);
  410. }
  411. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  412. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  413. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  414. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  415. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  416. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  417. #ifdef GL_SGIX_shadow
  418. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_OPERATOR_SGIX,
  419. GL_TEXTURE_LEQUAL_R_SGIX);
  420. #endif
  421. #ifdef GL_SGIX_shadow_ambient
  422. if (glutExtensionSupported("GL_SGIX_shadow_ambient"))
  423. glTexParameterf(GL_TEXTURE_2D, GL_SHADOW_AMBIENT_SGIX, 0.3);
  424. #endif
  425. /* setup 1-D grayscale texture image for SHOW_DISTANCE mode */
  426. {
  427. GLuint i;
  428. GLubyte image[256];
  429. for (i = 0; i < 256; i++)
  430. image[i] = i;
  431. glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
  432. 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
  433. }
  434. glEnable(GL_DEPTH_TEST);
  435. glEnable(GL_LIGHTING);
  436. glEnable(GL_LIGHT0);
  437. }
  438. static void
  439. PrintHelp(void)
  440. {
  441. printf("Keys:\n");
  442. printf(" a = toggle animation\n");
  443. printf(" i = show depth texture image\n");
  444. printf(" m = show depth texture mapping\n");
  445. printf(" d = show fragment distance from light source\n");
  446. printf(" n = show normal, shadowed image\n");
  447. printf(" f = toggle nearest/bilinear texture filtering\n");
  448. printf(" b/B = decrease/increase shadow map Z bias\n");
  449. printf(" cursor keys = rotate scene\n");
  450. printf(" <shift> + cursor keys = rotate light source\n");
  451. }
  452. int
  453. main(int argc, char *argv[])
  454. {
  455. glutInit(&argc, argv);
  456. glutInitWindowPosition(0, 0);
  457. glutInitWindowSize(WindowWidth, WindowHeight);
  458. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  459. glutCreateWindow(argv[0]);
  460. glutReshapeFunc(Reshape);
  461. glutKeyboardFunc(Key);
  462. glutSpecialFunc(SpecialKey);
  463. glutDisplayFunc(Display);
  464. if (Anim)
  465. glutIdleFunc(Idle);
  466. Init();
  467. PrintHelp();
  468. glutMainLoop();
  469. return 0;
  470. }