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.

shadowtex.c 28KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. /*
  2. * Shadow demo using the GL_ARB_depth_texture, GL_ARB_shadow and
  3. * GL_ARB_shadow_ambient extensions.
  4. *
  5. * Brian Paul
  6. * 19 Feb 2001
  7. *
  8. * Added GL_EXT_shadow_funcs support on 23 March 2002
  9. * Added GL_EXT_packed_depth_stencil support on 15 March 2006.
  10. * Added GL_EXT_framebuffer_object support on 27 March 2006.
  11. * Removed old SGIX extension support on 5 April 2006.
  12. * Added vertex / fragment program support on 7 June 2007 (Ian Romanick).
  13. *
  14. * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
  15. *
  16. * Permission is hereby granted, free of charge, to any person obtaining a
  17. * copy of this software and associated documentation files (the "Software"),
  18. * to deal in the Software without restriction, including without limitation
  19. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  20. * and/or sell copies of the Software, and to permit persons to whom the
  21. * Software is furnished to do so, subject to the following conditions:
  22. *
  23. * The above copyright notice and this permission notice shall be included
  24. * in all copies or substantial portions of the Software.
  25. *
  26. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  27. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  28. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  29. * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
  30. * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  31. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  32. */
  33. #define GL_GLEXT_PROTOTYPES
  34. #include <assert.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <math.h>
  39. #include <GL/glut.h>
  40. #include "showbuffer.h"
  41. #define DEG_TO_RAD (3.14159 / 180.0)
  42. static GLint WindowWidth = 450, WindowHeight = 300;
  43. static GLfloat Xrot = 15, Yrot = 0, Zrot = 0;
  44. static GLfloat Red[4] = {1, 0, 0, 1};
  45. static GLfloat Green[4] = {0, 1, 0, 1};
  46. static GLfloat Blue[4] = {0, 0, 1, 1};
  47. static GLfloat Yellow[4] = {1, 1, 0, 1};
  48. static GLfloat LightDist = 10;
  49. static GLfloat LightLatitude = 45.0;
  50. static GLfloat LightLongitude = 45.0;
  51. static GLfloat LightPos[4];
  52. static GLfloat SpotDir[3];
  53. static GLfloat SpotAngle = 40.0 * DEG_TO_RAD;
  54. static GLfloat ShadowNear = 4.0, ShadowFar = 24.0;
  55. static GLint ShadowTexWidth = 256, ShadowTexHeight = 256;
  56. static GLboolean LinearFilter = GL_FALSE;
  57. static GLfloat Bias = -0.06;
  58. static GLboolean Anim = GL_TRUE;
  59. static GLboolean NeedNewShadowMap = GL_FALSE;
  60. static GLuint ShadowTexture, GrayTexture;
  61. static GLuint ShadowFBO;
  62. static GLfloat lightModelview[16];
  63. static GLfloat lightProjection[16];
  64. static GLuint vert_prog;
  65. static GLuint frag_progs[3];
  66. static GLuint curr_frag = 0;
  67. static GLuint max_frag = 1;
  68. #define NUM_FRAG_MODES 3
  69. static const char *FragProgNames[] = {
  70. "fixed-function",
  71. "program without \"OPTION ARB_fragment_program_shadow\"",
  72. "program with \"OPTION ARB_fragment_program_shadow\"",
  73. };
  74. static GLboolean HaveFBO = GL_FALSE;
  75. static GLboolean UseFBO = GL_FALSE;
  76. static GLboolean HaveVP = GL_FALSE;
  77. static GLboolean HaveFP = GL_FALSE;
  78. static GLboolean HaveFP_Shadow = GL_FALSE;
  79. static GLboolean UseVP = GL_FALSE;
  80. static GLboolean HavePackedDepthStencil = GL_FALSE;
  81. static GLboolean UsePackedDepthStencil = GL_FALSE;
  82. static GLboolean HaveEXTshadowFuncs = GL_FALSE;
  83. static GLboolean HaveShadowAmbient = GL_FALSE;
  84. static GLint Operator = 0;
  85. static const GLenum OperatorFunc[8] = {
  86. GL_LEQUAL, GL_LESS, GL_GEQUAL, GL_GREATER,
  87. GL_EQUAL, GL_NOTEQUAL, GL_ALWAYS, GL_NEVER };
  88. static const char *OperatorName[8] = {
  89. "GL_LEQUAL", "GL_LESS", "GL_GEQUAL", "GL_GREATER",
  90. "GL_EQUAL", "GL_NOTEQUAL", "GL_ALWAYS", "GL_NEVER" };
  91. static GLuint DisplayMode;
  92. #define SHOW_SHADOWS 0
  93. #define SHOW_DEPTH_IMAGE 1
  94. #define SHOW_DEPTH_MAPPING 2
  95. #define SHOW_DISTANCE 3
  96. #define MAT4_MUL(dest_vec, src_mat, src_vec) \
  97. "DP4 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
  98. "DP4 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
  99. "DP4 " dest_vec ".z, " src_mat "[2], " src_vec ";\n" \
  100. "DP4 " dest_vec ".w, " src_mat "[3], " src_vec ";\n"
  101. #define MAT3_MUL(dest_vec, src_mat, src_vec) \
  102. "DP3 " dest_vec ".x, " src_mat "[0], " src_vec ";\n" \
  103. "DP3 " dest_vec ".y, " src_mat "[1], " src_vec ";\n" \
  104. "DP3 " dest_vec ".z, " src_mat "[2], " src_vec ";\n"
  105. #define NORMALIZE(dest, src) \
  106. "DP3 " dest ".w, " src ", " src ";\n" \
  107. "RSQ " dest ".w, " dest ".w;\n" \
  108. "MUL " dest ", " src ", " dest ".w;\n"
  109. /**
  110. * Vertex program for shadow mapping.
  111. */
  112. static const char vert_code[] =
  113. "!!ARBvp1.0\n"
  114. "ATTRIB iPos = vertex.position;\n"
  115. "ATTRIB iNorm = vertex.normal;\n"
  116. "PARAM mvinv[4] = { state.matrix.modelview.invtrans };\n"
  117. "PARAM mvp[4] = { state.matrix.mvp };\n"
  118. "PARAM mv[4] = { state.matrix.modelview };\n"
  119. "PARAM texmat[4] = { state.matrix.texture[0] };\n"
  120. "PARAM lightPos = state.light[0].position;\n"
  121. "PARAM ambientCol = state.lightprod[0].ambient;\n"
  122. "PARAM diffuseCol = state.lightprod[0].diffuse;\n"
  123. "TEMP n, lightVec;\n"
  124. "ALIAS V = lightVec;\n"
  125. "ALIAS NdotL = n;\n"
  126. "OUTPUT oPos = result.position;\n"
  127. "OUTPUT oColor = result.color;\n"
  128. "OUTPUT oTex = result.texcoord[0];\n"
  129. /* Transform the vertex to clip coordinates. */
  130. MAT4_MUL("oPos", "mvp", "iPos")
  131. /* Transform the vertex to eye coordinates. */
  132. MAT4_MUL("V", "mv", "iPos")
  133. /* Transform the vertex to projected light coordinates. */
  134. MAT4_MUL("oTex", "texmat", "iPos")
  135. /* Transform the normal to eye coordinates. */
  136. MAT3_MUL("n", "mvinv", "iNorm")
  137. /* Calculate the vector from the vertex to the light in eye
  138. * coordinates.
  139. */
  140. "SUB lightVec, lightPos, V;\n"
  141. NORMALIZE("lightVec", "lightVec")
  142. /* Compute diffuse lighting coefficient.
  143. */
  144. "DP3 NdotL.x, n, lightVec;\n"
  145. "MAX NdotL.x, NdotL.x, {0.0};\n"
  146. "MIN NdotL.x, NdotL.x, {1.0};\n"
  147. /* Accumulate color contributions.
  148. */
  149. "MOV oColor, diffuseCol;\n"
  150. "MAD oColor.xyz, NdotL.x, diffuseCol, ambientCol;\n"
  151. "END\n"
  152. ;
  153. static const char frag_code[] =
  154. "!!ARBfp1.0\n"
  155. "TEMP shadow, temp;\n"
  156. "TXP shadow, fragment.texcoord[0], texture[0], 2D;\n"
  157. "RCP temp.x, fragment.texcoord[0].w;\n"
  158. "MUL temp.x, temp.x, fragment.texcoord[0].z;\n"
  159. "SGE shadow, shadow.x, temp.x;\n"
  160. "MUL result.color.rgb, fragment.color, shadow.x;\n"
  161. "MOV result.color.a, fragment.color;\n"
  162. "END\n"
  163. ;
  164. static const char frag_shadow_code[] =
  165. "!!ARBfp1.0\n"
  166. "OPTION ARB_fragment_program_shadow;\n"
  167. "TEMP shadow;\n"
  168. "TXP shadow, fragment.texcoord[0], texture[0], SHADOW2D;\n"
  169. "MUL result.color.rgb, fragment.color, shadow.x;\n"
  170. "MOV result.color.a, fragment.color.a;\n"
  171. "END\n"
  172. ;
  173. static void
  174. DrawScene(void)
  175. {
  176. GLfloat k = 6;
  177. /* sphere */
  178. glPushMatrix();
  179. glTranslatef(1.6, 2.2, 2.7);
  180. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Green);
  181. glColor4fv(Green);
  182. glutSolidSphere(1.5, 15, 15);
  183. glPopMatrix();
  184. /* dodecahedron */
  185. glPushMatrix();
  186. glTranslatef(-2.0, 1.2, 2.1);
  187. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Red);
  188. glColor4fv(Red);
  189. glutSolidDodecahedron();
  190. glPopMatrix();
  191. /* icosahedron */
  192. glPushMatrix();
  193. glTranslatef(-0.6, 1.3, -0.5);
  194. glScalef(1.5, 1.5, 1.5);
  195. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Yellow);
  196. glColor4fv(Red);
  197. glutSolidIcosahedron();
  198. glPopMatrix();
  199. /* a plane */
  200. glPushMatrix();
  201. glTranslatef(0, -1.1, 0);
  202. glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, Blue);
  203. glColor4fv(Blue);
  204. glNormal3f(0, 1, 0);
  205. glBegin(GL_POLYGON);
  206. glVertex3f(-k, 0, -k);
  207. glVertex3f( k, 0, -k);
  208. glVertex3f( k, 0, k);
  209. glVertex3f(-k, 0, k);
  210. glEnd();
  211. glPopMatrix();
  212. }
  213. /**
  214. * Calculate modelview and project matrices for the light
  215. *
  216. * Stores the results in \c lightProjection (projection matrix) and
  217. * \c lightModelview (modelview matrix).
  218. */
  219. static void
  220. MakeShadowMatrix(const GLfloat lightPos[4], const GLfloat spotDir[3],
  221. GLfloat spotAngle, GLfloat shadowNear, GLfloat shadowFar)
  222. {
  223. /* compute frustum to enclose spot light cone */
  224. const GLfloat d = shadowNear * tan(spotAngle);
  225. glMatrixMode(GL_PROJECTION);
  226. glPushMatrix();
  227. glLoadIdentity();
  228. glFrustum(-d, d, -d, d, shadowNear, shadowFar);
  229. glGetFloatv(GL_PROJECTION_MATRIX, lightProjection);
  230. glPopMatrix();
  231. glMatrixMode(GL_MODELVIEW);
  232. glPushMatrix();
  233. glLoadIdentity();
  234. gluLookAt(lightPos[0], lightPos[1], lightPos[2],
  235. lightPos[0] + spotDir[0],
  236. lightPos[1] + spotDir[1],
  237. lightPos[2] + spotDir[2],
  238. 0.0, 1.0, 0.0);
  239. glGetFloatv(GL_MODELVIEW_MATRIX, lightModelview);
  240. glPopMatrix();
  241. }
  242. /**
  243. * Load \c GL_TEXTURE matrix with light's MVP matrix.
  244. */
  245. static void SetShadowTextureMatrix(void)
  246. {
  247. static const GLfloat biasMatrix[16] = {
  248. 0.5, 0.0, 0.0, 0.0,
  249. 0.0, 0.5, 0.0, 0.0,
  250. 0.0, 0.0, 0.5, 0.0,
  251. 0.5, 0.5, 0.5, 1.0,
  252. };
  253. glMatrixMode(GL_TEXTURE);
  254. glLoadMatrixf(biasMatrix);
  255. glTranslatef(0.0, 0.0, Bias);
  256. glMultMatrixf(lightProjection);
  257. glMultMatrixf(lightModelview);
  258. glMatrixMode(GL_MODELVIEW);
  259. }
  260. static void
  261. EnableIdentityTexgen(void)
  262. {
  263. /* texgen so that texcoord = vertex coord */
  264. static GLfloat sPlane[4] = { 1, 0, 0, 0 };
  265. static GLfloat tPlane[4] = { 0, 1, 0, 0 };
  266. static GLfloat rPlane[4] = { 0, 0, 1, 0 };
  267. static GLfloat qPlane[4] = { 0, 0, 0, 1 };
  268. glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
  269. glTexGenfv(GL_T, GL_EYE_PLANE, tPlane);
  270. glTexGenfv(GL_R, GL_EYE_PLANE, rPlane);
  271. glTexGenfv(GL_Q, GL_EYE_PLANE, qPlane);
  272. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  273. glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  274. glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  275. glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  276. glEnable(GL_TEXTURE_GEN_S);
  277. glEnable(GL_TEXTURE_GEN_T);
  278. glEnable(GL_TEXTURE_GEN_R);
  279. glEnable(GL_TEXTURE_GEN_Q);
  280. }
  281. /*
  282. * Setup 1-D texgen so that the distance from the light source, between
  283. * the near and far planes maps to s=0 and s=1. When we draw the scene,
  284. * the grayness will indicate the fragment's distance from the light
  285. * source.
  286. */
  287. static void
  288. EnableDistanceTexgen(const GLfloat lightPos[4], const GLfloat lightDir[3],
  289. GLfloat lightNear, GLfloat lightFar)
  290. {
  291. GLfloat m, d;
  292. GLfloat sPlane[4];
  293. GLfloat nearPoint[3];
  294. m = sqrt(lightDir[0] * lightDir[0] +
  295. lightDir[1] * lightDir[1] +
  296. lightDir[2] * lightDir[2]);
  297. d = lightFar - lightNear;
  298. /* nearPoint = point on light direction vector which intersects the
  299. * near plane of the light frustum.
  300. */
  301. nearPoint[0] = lightPos[0] + lightDir[0] / m * lightNear;
  302. nearPoint[1] = lightPos[1] + lightDir[1] / m * lightNear;
  303. nearPoint[2] = lightPos[2] + lightDir[2] / m * lightNear;
  304. sPlane[0] = lightDir[0] / d / m;
  305. sPlane[1] = lightDir[1] / d / m;
  306. sPlane[2] = lightDir[2] / d / m;
  307. sPlane[3] = -(sPlane[0] * nearPoint[0]
  308. + sPlane[1] * nearPoint[1]
  309. + sPlane[2] * nearPoint[2]);
  310. glTexGenfv(GL_S, GL_EYE_PLANE, sPlane);
  311. glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
  312. glEnable(GL_TEXTURE_GEN_S);
  313. }
  314. static void
  315. DisableTexgen(void)
  316. {
  317. glDisable(GL_TEXTURE_GEN_S);
  318. glDisable(GL_TEXTURE_GEN_T);
  319. glDisable(GL_TEXTURE_GEN_R);
  320. glDisable(GL_TEXTURE_GEN_Q);
  321. }
  322. static void
  323. ComputeLightPos(GLfloat dist, GLfloat latitude, GLfloat longitude,
  324. GLfloat pos[4], GLfloat dir[3])
  325. {
  326. pos[0] = dist * sin(longitude * DEG_TO_RAD);
  327. pos[1] = dist * sin(latitude * DEG_TO_RAD);
  328. pos[2] = dist * cos(latitude * DEG_TO_RAD) * cos(longitude * DEG_TO_RAD);
  329. pos[3] = 1;
  330. dir[0] = -pos[0];
  331. dir[1] = -pos[1];
  332. dir[2] = -pos[2];
  333. }
  334. /**
  335. * Render the shadow map / depth texture.
  336. * The result will be in the texture object named ShadowTexture.
  337. */
  338. static void
  339. RenderShadowMap(void)
  340. {
  341. GLenum depthFormat; /* GL_DEPTH_COMPONENT or GL_DEPTH_STENCIL_EXT */
  342. GLenum depthType; /* GL_UNSIGNED_INT_24_8_EXT or GL_UNSIGNED_INT */
  343. if (WindowWidth >= 1024 && WindowHeight >= 1024) {
  344. ShadowTexWidth = ShadowTexHeight = 1024;
  345. }
  346. else if (WindowWidth >= 512 && WindowHeight >= 512) {
  347. ShadowTexWidth = ShadowTexHeight = 512;
  348. }
  349. else if (WindowWidth >= 256 && WindowHeight >= 256) {
  350. ShadowTexWidth = ShadowTexHeight = 256;
  351. }
  352. else {
  353. ShadowTexWidth = ShadowTexHeight = 128;
  354. }
  355. printf("Rendering %d x %d depth texture\n", ShadowTexWidth, ShadowTexHeight);
  356. if (UsePackedDepthStencil) {
  357. depthFormat = GL_DEPTH_STENCIL_EXT;
  358. depthType = GL_UNSIGNED_INT_24_8_EXT;
  359. }
  360. else {
  361. depthFormat = GL_DEPTH_COMPONENT;
  362. depthType = GL_UNSIGNED_INT;
  363. }
  364. glMatrixMode(GL_PROJECTION);
  365. glLoadMatrixf(lightProjection);
  366. glMatrixMode(GL_MODELVIEW);
  367. glLoadMatrixf(lightModelview);
  368. if (UseFBO) {
  369. GLenum fbo_status;
  370. glTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
  371. ShadowTexWidth, ShadowTexHeight, 0,
  372. depthFormat, depthType, NULL);
  373. /* Set the filter mode so that the texture is texture-complete.
  374. * Otherwise it will cause the framebuffer to fail the framebuffer
  375. * completeness test.
  376. */
  377. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  378. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
  379. glDrawBuffer(GL_NONE);
  380. glReadBuffer(GL_NONE);
  381. fbo_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
  382. if (fbo_status != GL_FRAMEBUFFER_COMPLETE_EXT) {
  383. fprintf(stderr, "FBO not complete! status = 0x%04x\n", fbo_status);
  384. assert(fbo_status == GL_FRAMEBUFFER_COMPLETE_EXT);
  385. }
  386. }
  387. assert(!glIsEnabled(GL_TEXTURE_1D));
  388. assert(!glIsEnabled(GL_TEXTURE_2D));
  389. glViewport(0, 0, ShadowTexWidth, ShadowTexHeight);
  390. glClear(GL_DEPTH_BUFFER_BIT);
  391. glEnable(GL_DEPTH_TEST);
  392. DrawScene();
  393. if (UseFBO) {
  394. /* all done! */
  395. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  396. }
  397. else {
  398. /*
  399. * copy depth buffer into the texture map
  400. */
  401. if (DisplayMode == SHOW_DEPTH_MAPPING) {
  402. /* load depth image as gray-scale luminance texture */
  403. GLuint *depth = (GLuint *)
  404. malloc(ShadowTexWidth * ShadowTexHeight * sizeof(GLuint));
  405. assert(depth);
  406. glReadPixels(0, 0, ShadowTexWidth, ShadowTexHeight,
  407. depthFormat, depthType, depth);
  408. glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,
  409. ShadowTexWidth, ShadowTexHeight, 0,
  410. GL_LUMINANCE, GL_UNSIGNED_INT, depth);
  411. free(depth);
  412. }
  413. else {
  414. /* The normal shadow case - a real depth texture */
  415. glCopyTexImage2D(GL_TEXTURE_2D, 0, depthFormat,
  416. 0, 0, ShadowTexWidth, ShadowTexHeight, 0);
  417. if (UsePackedDepthStencil) {
  418. /* debug check */
  419. GLint intFormat;
  420. glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
  421. GL_TEXTURE_INTERNAL_FORMAT, &intFormat);
  422. assert(intFormat == GL_DEPTH_STENCIL_EXT);
  423. }
  424. }
  425. }
  426. }
  427. /**
  428. * Show the shadow map as a grayscale image.
  429. */
  430. static void
  431. ShowShadowMap(void)
  432. {
  433. glClear(GL_COLOR_BUFFER_BIT);
  434. glMatrixMode(GL_TEXTURE);
  435. glLoadIdentity();
  436. glMatrixMode(GL_PROJECTION);
  437. glLoadIdentity();
  438. glOrtho(0, WindowWidth, 0, WindowHeight, -1, 1);
  439. glMatrixMode(GL_MODELVIEW);
  440. glLoadIdentity();
  441. glDisable(GL_DEPTH_TEST);
  442. glDisable(GL_LIGHTING);
  443. glEnable(GL_TEXTURE_2D);
  444. DisableTexgen();
  445. /* interpret texture's depth values as luminance values */
  446. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
  447. glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
  448. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  449. glBegin(GL_POLYGON);
  450. glTexCoord2f(0, 0); glVertex2f(0, 0);
  451. glTexCoord2f(1, 0); glVertex2f(ShadowTexWidth, 0);
  452. glTexCoord2f(1, 1); glVertex2f(ShadowTexWidth, ShadowTexHeight);
  453. glTexCoord2f(0, 1); glVertex2f(0, ShadowTexHeight);
  454. glEnd();
  455. glDisable(GL_TEXTURE_2D);
  456. glEnable(GL_DEPTH_TEST);
  457. glEnable(GL_LIGHTING);
  458. }
  459. /**
  460. * Redraw window image
  461. */
  462. static void
  463. Display(void)
  464. {
  465. GLenum error;
  466. ComputeLightPos(LightDist, LightLatitude, LightLongitude,
  467. LightPos, SpotDir);
  468. if (NeedNewShadowMap) {
  469. MakeShadowMatrix(LightPos, SpotDir, SpotAngle, ShadowNear, ShadowFar);
  470. RenderShadowMap();
  471. NeedNewShadowMap = GL_FALSE;
  472. }
  473. glViewport(0, 0, WindowWidth, WindowHeight);
  474. if (DisplayMode == SHOW_DEPTH_IMAGE) {
  475. ShowShadowMap();
  476. }
  477. else {
  478. /* prepare to draw scene from camera's view */
  479. const GLfloat ar = (GLfloat) WindowWidth / (GLfloat) WindowHeight;
  480. glMatrixMode(GL_PROJECTION);
  481. glLoadIdentity();
  482. glFrustum(-ar, ar, -1.0, 1.0, 4.0, 50.0);
  483. glMatrixMode(GL_MODELVIEW);
  484. glLoadIdentity();
  485. glTranslatef(0.0, 0.0, -22.0);
  486. glRotatef(Xrot, 1, 0, 0);
  487. glRotatef(Yrot, 0, 1, 0);
  488. glRotatef(Zrot, 0, 0, 1);
  489. glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  490. glLightfv(GL_LIGHT0, GL_POSITION, LightPos);
  491. if (LinearFilter) {
  492. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  493. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  494. }
  495. else {
  496. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  497. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  498. }
  499. if (DisplayMode == SHOW_DEPTH_MAPPING) {
  500. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
  501. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  502. glEnable(GL_TEXTURE_2D);
  503. SetShadowTextureMatrix();
  504. EnableIdentityTexgen();
  505. }
  506. else if (DisplayMode == SHOW_DISTANCE) {
  507. glMatrixMode(GL_TEXTURE);
  508. glLoadIdentity();
  509. glMatrixMode(GL_MODELVIEW);
  510. EnableDistanceTexgen(LightPos, SpotDir, ShadowNear+Bias, ShadowFar);
  511. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  512. glEnable(GL_TEXTURE_1D);
  513. assert(!glIsEnabled(GL_TEXTURE_2D));
  514. }
  515. else {
  516. assert(DisplayMode == SHOW_SHADOWS);
  517. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
  518. GL_COMPARE_R_TO_TEXTURE_ARB);
  519. if (curr_frag > 0) {
  520. glEnable(GL_FRAGMENT_PROGRAM_ARB);
  521. }
  522. else {
  523. glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  524. }
  525. glEnable(GL_TEXTURE_2D);
  526. SetShadowTextureMatrix();
  527. if (UseVP) {
  528. glEnable(GL_VERTEX_PROGRAM_ARB);
  529. }
  530. else {
  531. glEnable(GL_LIGHTING);
  532. EnableIdentityTexgen();
  533. }
  534. }
  535. DrawScene();
  536. if (UseVP) {
  537. glDisable(GL_VERTEX_PROGRAM_ARB);
  538. }
  539. else {
  540. DisableTexgen();
  541. glDisable(GL_LIGHTING);
  542. }
  543. if (curr_frag > 0) {
  544. glDisable(GL_FRAGMENT_PROGRAM_ARB);
  545. }
  546. glDisable(GL_TEXTURE_2D);
  547. }
  548. glutSwapBuffers();
  549. error = glGetError();
  550. if (error) {
  551. printf("GL Error: %s\n", (char *) gluErrorString(error));
  552. }
  553. }
  554. static void
  555. Reshape(int width, int height)
  556. {
  557. WindowWidth = width;
  558. WindowHeight = height;
  559. NeedNewShadowMap = GL_TRUE;
  560. }
  561. static void
  562. Idle(void)
  563. {
  564. static double t0 = -1.;
  565. double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  566. if (t0 < 0.0)
  567. t0 = t;
  568. dt = t - t0;
  569. t0 = t;
  570. Yrot += 75.0 * dt;
  571. /*LightLongitude -= 5.0;*/
  572. glutPostRedisplay();
  573. }
  574. static void
  575. Key(unsigned char key, int x, int y)
  576. {
  577. const GLfloat step = 3.0;
  578. (void) x;
  579. (void) y;
  580. switch (key) {
  581. case 'a':
  582. Anim = !Anim;
  583. if (Anim)
  584. glutIdleFunc(Idle);
  585. else
  586. glutIdleFunc(NULL);
  587. break;
  588. case 'b':
  589. Bias -= 0.01;
  590. printf("Bias %g\n", Bias);
  591. break;
  592. case 'B':
  593. Bias += 0.01;
  594. printf("Bias %g\n", Bias);
  595. break;
  596. case 'd':
  597. DisplayMode = SHOW_DISTANCE;
  598. break;
  599. case 'f':
  600. LinearFilter = !LinearFilter;
  601. printf("%s filtering\n", LinearFilter ? "Bilinear" : "Nearest");
  602. break;
  603. case 'i':
  604. DisplayMode = SHOW_DEPTH_IMAGE;
  605. break;
  606. case 'm':
  607. DisplayMode = SHOW_DEPTH_MAPPING;
  608. break;
  609. case 'M':
  610. curr_frag = (1 + curr_frag) % max_frag;
  611. printf("Using fragment %s\n", FragProgNames[curr_frag]);
  612. if (HaveFP) {
  613. glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, frag_progs[curr_frag]);
  614. }
  615. break;
  616. case 'n':
  617. case 's':
  618. case ' ':
  619. DisplayMode = SHOW_SHADOWS;
  620. break;
  621. case 'o':
  622. if (HaveEXTshadowFuncs) {
  623. Operator++;
  624. if (Operator >= 8)
  625. Operator = 0;
  626. printf("Operator: %s\n", OperatorName[Operator]);
  627. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB,
  628. OperatorFunc[Operator]);
  629. }
  630. break;
  631. case 'p':
  632. UsePackedDepthStencil = !UsePackedDepthStencil;
  633. if (UsePackedDepthStencil && !HavePackedDepthStencil) {
  634. printf("Sorry, GL_EXT_packed_depth_stencil not supported\n");
  635. UsePackedDepthStencil = GL_FALSE;
  636. }
  637. else {
  638. printf("Use GL_DEPTH_STENCIL_EXT: %d\n", UsePackedDepthStencil);
  639. /* Don't really need to regenerate shadow map texture, but do so
  640. * to exercise more code more often.
  641. */
  642. NeedNewShadowMap = GL_TRUE;
  643. }
  644. break;
  645. case 'v':
  646. UseVP = !UseVP && HaveVP;
  647. printf("Using vertex %s mode.\n",
  648. UseVP ? "program" : "fixed-function");
  649. break;
  650. case 'z':
  651. Zrot -= step;
  652. break;
  653. case 'Z':
  654. Zrot += step;
  655. break;
  656. case 27:
  657. exit(0);
  658. break;
  659. }
  660. glutPostRedisplay();
  661. }
  662. static void
  663. SpecialKey(int key, int x, int y)
  664. {
  665. const GLfloat step = 3.0;
  666. const int mod = glutGetModifiers();
  667. (void) x;
  668. (void) y;
  669. switch (key) {
  670. case GLUT_KEY_UP:
  671. if (mod)
  672. LightLatitude += step;
  673. else
  674. Xrot += step;
  675. break;
  676. case GLUT_KEY_DOWN:
  677. if (mod)
  678. LightLatitude -= step;
  679. else
  680. Xrot -= step;
  681. break;
  682. case GLUT_KEY_LEFT:
  683. if (mod)
  684. LightLongitude += step;
  685. else
  686. Yrot += step;
  687. break;
  688. case GLUT_KEY_RIGHT:
  689. if (mod)
  690. LightLongitude -= step;
  691. else
  692. Yrot -= step;
  693. break;
  694. }
  695. if (mod)
  696. NeedNewShadowMap = GL_TRUE;
  697. glutPostRedisplay();
  698. }
  699. /* A helper for finding errors in program strings */
  700. static int FindLine( const char *program, int position )
  701. {
  702. int i, line = 1;
  703. for (i = 0; i < position; i++) {
  704. if (program[i] == '\n')
  705. line++;
  706. }
  707. return line;
  708. }
  709. static GLuint
  710. compile_program(GLenum target, const char *code)
  711. {
  712. GLuint p;
  713. GLint errorPos;
  714. glGenProgramsARB(1, & p);
  715. glBindProgramARB(target, p);
  716. glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB,
  717. strlen(code), code);
  718. glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errorPos);
  719. if (glGetError() != GL_NO_ERROR || errorPos != -1) {
  720. int l = FindLine(code, errorPos);
  721. printf("Fragment Program Error (pos=%d line=%d): %s\n", errorPos, l,
  722. (char *) glGetString(GL_PROGRAM_ERROR_STRING_ARB));
  723. exit(0);
  724. }
  725. glBindProgramARB(target, 0);
  726. return p;
  727. }
  728. static void
  729. Init(void)
  730. {
  731. static const GLfloat borderColor[4] = {1.0, 0.0, 0.0, 0.0};
  732. if (!glutExtensionSupported("GL_ARB_depth_texture") ||
  733. !glutExtensionSupported("GL_ARB_shadow")) {
  734. printf("Sorry, this demo requires the GL_ARB_depth_texture and GL_ARB_shadow extensions\n");
  735. exit(1);
  736. }
  737. printf("Using GL_ARB_depth_texture and GL_ARB_shadow\n");
  738. HaveVP = glutExtensionSupported("GL_ARB_vertex_program");
  739. HaveFP = glutExtensionSupported("GL_ARB_fragment_program");
  740. HaveFP_Shadow = glutExtensionSupported("GL_ARB_fragment_program_shadow");
  741. HaveShadowAmbient = glutExtensionSupported("GL_ARB_shadow_ambient");
  742. if (HaveShadowAmbient) {
  743. printf("and GL_ARB_shadow_ambient\n");
  744. }
  745. HaveEXTshadowFuncs = glutExtensionSupported("GL_EXT_shadow_funcs");
  746. HavePackedDepthStencil = glutExtensionSupported("GL_EXT_packed_depth_stencil");
  747. UsePackedDepthStencil = HavePackedDepthStencil;
  748. #if defined(GL_EXT_framebuffer_object)
  749. HaveFBO = glutExtensionSupported("GL_EXT_framebuffer_object");
  750. UseFBO = HaveFBO;
  751. if (UseFBO) {
  752. printf("Using GL_EXT_framebuffer_object\n");
  753. }
  754. #endif
  755. /*
  756. * Set up the 2D shadow map texture
  757. */
  758. glGenTextures(1, &ShadowTexture);
  759. glBindTexture(GL_TEXTURE_2D, ShadowTexture);
  760. glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
  761. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  762. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  763. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB,
  764. GL_COMPARE_R_TO_TEXTURE_ARB);
  765. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
  766. if (HaveShadowAmbient) {
  767. glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FAIL_VALUE_ARB, 0.3);
  768. }
  769. #if defined(GL_EXT_framebuffer_object)
  770. if (UseFBO) {
  771. glGenFramebuffersEXT(1, &ShadowFBO);
  772. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ShadowFBO);
  773. glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT,
  774. GL_COLOR_ATTACHMENT0_EXT,
  775. GL_RENDERBUFFER_EXT, 0);
  776. glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
  777. GL_TEXTURE_2D, ShadowTexture, 0);
  778. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
  779. }
  780. #endif
  781. /*
  782. * Setup 1-D grayscale texture image for SHOW_DISTANCE mode
  783. */
  784. glGenTextures(1, &GrayTexture);
  785. glBindTexture(GL_TEXTURE_1D, GrayTexture);
  786. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP);
  787. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP);
  788. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  789. glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  790. {
  791. GLuint i;
  792. GLubyte image[256];
  793. for (i = 0; i < 256; i++)
  794. image[i] = i;
  795. glTexImage1D(GL_TEXTURE_1D, 0, GL_LUMINANCE,
  796. 256, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, image);
  797. }
  798. if (HaveVP) {
  799. vert_prog = compile_program(GL_VERTEX_PROGRAM_ARB, vert_code);
  800. glBindProgramARB(GL_VERTEX_PROGRAM_ARB, vert_prog);
  801. }
  802. max_frag = 1;
  803. frag_progs[0] = 0;
  804. if (HaveFP) {
  805. frag_progs[1] = compile_program(GL_FRAGMENT_PROGRAM_ARB, frag_code);
  806. max_frag = 2;
  807. }
  808. if (HaveFP && HaveFP_Shadow) {
  809. frag_progs[2] = compile_program(GL_FRAGMENT_PROGRAM_ARB,
  810. frag_shadow_code);
  811. max_frag = 3;
  812. }
  813. glEnable(GL_DEPTH_TEST);
  814. glEnable(GL_LIGHTING);
  815. glEnable(GL_LIGHT0);
  816. }
  817. static void
  818. PrintHelp(void)
  819. {
  820. printf("Keys:\n");
  821. printf(" a = toggle animation\n");
  822. printf(" i = show depth texture image\n");
  823. printf(" m = show depth texture mapping\n");
  824. printf(" d = show fragment distance from light source\n");
  825. printf(" n = show normal, shadowed image\n");
  826. printf(" f = toggle nearest/bilinear texture filtering\n");
  827. printf(" b/B = decrease/increase shadow map Z bias\n");
  828. printf(" p = toggle use of packed depth/stencil\n");
  829. printf(" M = cycle through fragment program modes\n");
  830. printf(" v = toggle vertex program modes\n");
  831. printf(" cursor keys = rotate scene\n");
  832. printf(" <shift> + cursor keys = rotate light source\n");
  833. if (HaveEXTshadowFuncs)
  834. printf(" o = cycle through comparison modes\n");
  835. }
  836. int
  837. main(int argc, char *argv[])
  838. {
  839. glutInit(&argc, argv);
  840. glutInitWindowPosition(0, 0);
  841. glutInitWindowSize(WindowWidth, WindowHeight);
  842. glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL);
  843. glutCreateWindow(argv[0]);
  844. glutReshapeFunc(Reshape);
  845. glutKeyboardFunc(Key);
  846. glutSpecialFunc(SpecialKey);
  847. glutDisplayFunc(Display);
  848. if (Anim)
  849. glutIdleFunc(Idle);
  850. Init();
  851. PrintHelp();
  852. glutMainLoop();
  853. return 0;
  854. }