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.

reflect.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  1. /*
  2. * Demo of a reflective, texture-mapped surface with OpenGL.
  3. * Brian Paul August 14, 1995 This file is in the public domain.
  4. *
  5. * Hardware texture mapping is highly recommended!
  6. *
  7. * The basic steps are:
  8. * 1. Render the reflective object (a polygon) from the normal viewpoint,
  9. * setting the stencil planes = 1.
  10. * 2. Render the scene from a special viewpoint: the viewpoint which
  11. * is on the opposite side of the reflective plane. Only draw where
  12. * stencil = 1. This draws the objects in the reflective surface.
  13. * 3. Render the scene from the original viewpoint. This draws the
  14. * objects in the normal fashion. Use blending when drawing
  15. * the reflective, textured surface.
  16. *
  17. * This is a very crude demo. It could be much better.
  18. */
  19. /*
  20. * Authors:
  21. * Brian Paul
  22. * Dirk Reiners (reiners@igd.fhg.de) made some modifications to this code.
  23. * Mark Kilgard (April 1997)
  24. * Brian Paul (April 2000 - added keyboard d/s options)
  25. * Brian Paul (August 2005 - added multi window feature)
  26. */
  27. #include <assert.h>
  28. #include <math.h>
  29. #include <stdio.h>
  30. #include <stdlib.h>
  31. #include "GL/glut.h"
  32. #include "showbuffer.h"
  33. #include "readtex.h"
  34. #define DEG2RAD (3.14159/180.0)
  35. #define TABLE_TEXTURE "../images/tile.rgb"
  36. #define MAX_OBJECTS 2
  37. #define INIT_WIDTH 400
  38. #define INIT_HEIGHT 300
  39. #ifdef _WIN32
  40. #undef CreateWindowA
  41. #endif
  42. struct window {
  43. int id; /* returned by glutCreateWindow() */
  44. int width, height;
  45. GLboolean anim;
  46. GLfloat xrot, yrot;
  47. GLfloat spin;
  48. GLenum showBuffer;
  49. GLenum drawBuffer;
  50. GLuint table_list;
  51. GLuint objects_list[MAX_OBJECTS];
  52. double t0;
  53. struct window *next;
  54. };
  55. static struct window *FirstWindow = NULL;
  56. static void
  57. CreateWindow(void);
  58. static struct window *
  59. CurrentWindow(void)
  60. {
  61. int id = glutGetWindow();
  62. struct window *w;
  63. for (w = FirstWindow; w; w = w->next) {
  64. if (w->id == id)
  65. return w;
  66. }
  67. return NULL;
  68. }
  69. static GLboolean
  70. AnyAnimating(void)
  71. {
  72. struct window *w;
  73. for (w = FirstWindow; w; w = w->next) {
  74. if (w->anim)
  75. return 1;
  76. }
  77. return 0;
  78. }
  79. static void
  80. KillWindow(struct window *w)
  81. {
  82. struct window *win, *prev = NULL;
  83. for (win = FirstWindow; win; win = win->next) {
  84. if (win == w) {
  85. if (prev) {
  86. prev->next = win->next;
  87. }
  88. else {
  89. FirstWindow = win->next;
  90. }
  91. glutDestroyWindow(win->id);
  92. win->next = NULL;
  93. free(win);
  94. return;
  95. }
  96. prev = win;
  97. }
  98. }
  99. static void
  100. KillAllWindows(void)
  101. {
  102. while (FirstWindow)
  103. KillWindow(FirstWindow);
  104. }
  105. static GLuint
  106. MakeTable(void)
  107. {
  108. static GLfloat table_mat[] = { 1.0, 1.0, 1.0, 0.6 };
  109. static GLfloat gray[] = { 0.4, 0.4, 0.4, 1.0 };
  110. GLuint table_list;
  111. table_list = glGenLists(1);
  112. glNewList( table_list, GL_COMPILE );
  113. /* load table's texture */
  114. glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_mat );
  115. /*glMaterialfv( GL_FRONT, GL_EMISSION, gray );*/
  116. glMaterialfv( GL_FRONT, GL_DIFFUSE, table_mat );
  117. glMaterialfv( GL_FRONT, GL_AMBIENT, gray );
  118. /* draw textured square for the table */
  119. glPushMatrix();
  120. glScalef( 4.0, 4.0, 4.0 );
  121. glBegin( GL_POLYGON );
  122. glNormal3f( 0.0, 1.0, 0.0 );
  123. glTexCoord2f( 0.0, 0.0 ); glVertex3f( -1.0, 0.0, 1.0 );
  124. glTexCoord2f( 1.0, 0.0 ); glVertex3f( 1.0, 0.0, 1.0 );
  125. glTexCoord2f( 1.0, 1.0 ); glVertex3f( 1.0, 0.0, -1.0 );
  126. glTexCoord2f( 0.0, 1.0 ); glVertex3f( -1.0, 0.0, -1.0 );
  127. glEnd();
  128. glPopMatrix();
  129. glDisable( GL_TEXTURE_2D );
  130. glEndList();
  131. return table_list;
  132. }
  133. static void
  134. MakeObjects(GLuint *objects_list)
  135. {
  136. GLUquadricObj *q;
  137. static GLfloat cyan[] = { 0.0, 1.0, 1.0, 1.0 };
  138. static GLfloat green[] = { 0.2, 1.0, 0.2, 1.0 };
  139. static GLfloat black[] = { 0.0, 0.0, 0.0, 0.0 };
  140. q = gluNewQuadric();
  141. gluQuadricDrawStyle( q, GLU_FILL );
  142. gluQuadricNormals( q, GLU_SMOOTH );
  143. objects_list[0] = glGenLists(1);
  144. glNewList( objects_list[0], GL_COMPILE );
  145. glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, cyan );
  146. glMaterialfv( GL_FRONT, GL_EMISSION, black );
  147. gluCylinder( q, 0.5, 0.5, 1.0, 15, 1 );
  148. glEndList();
  149. objects_list[1] = glGenLists(1);
  150. glNewList( objects_list[1], GL_COMPILE );
  151. glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green );
  152. glMaterialfv( GL_FRONT, GL_EMISSION, black );
  153. gluCylinder( q, 1.5, 0.0, 2.5, 15, 1 );
  154. glEndList();
  155. gluDeleteQuadric(q);
  156. }
  157. static void
  158. InitWindow(struct window *w)
  159. {
  160. GLint imgWidth, imgHeight;
  161. GLenum imgFormat;
  162. GLubyte *image = NULL;
  163. w->table_list = MakeTable();
  164. MakeObjects(w->objects_list);
  165. image = LoadRGBImage( TABLE_TEXTURE, &imgWidth, &imgHeight, &imgFormat );
  166. if (!image) {
  167. printf("Couldn't read %s\n", TABLE_TEXTURE);
  168. exit(0);
  169. }
  170. gluBuild2DMipmaps(GL_TEXTURE_2D, 3, imgWidth, imgHeight,
  171. imgFormat, GL_UNSIGNED_BYTE, image);
  172. free(image);
  173. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
  174. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
  175. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
  176. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
  177. glShadeModel( GL_FLAT );
  178. glEnable( GL_LIGHT0 );
  179. glEnable( GL_LIGHTING );
  180. glClearColor( 0.5, 0.5, 0.9, 0.0 );
  181. glEnable( GL_NORMALIZE );
  182. }
  183. static void
  184. Reshape(int width, int height)
  185. {
  186. struct window *w = CurrentWindow();
  187. GLfloat yAspect = 2.5;
  188. GLfloat xAspect = yAspect * (float) width / (float) height;
  189. w->width = width;
  190. w->height = height;
  191. glViewport(0, 0, width, height);
  192. glMatrixMode(GL_PROJECTION);
  193. glLoadIdentity();
  194. glFrustum( -xAspect, xAspect, -yAspect, yAspect, 10.0, 30.0 );
  195. glMatrixMode(GL_MODELVIEW);
  196. glLoadIdentity();
  197. }
  198. static void
  199. DrawObjects(struct window *w, GLfloat eyex, GLfloat eyey, GLfloat eyez)
  200. {
  201. (void) eyex;
  202. (void) eyey;
  203. (void) eyez;
  204. #ifndef USE_ZBUFFER
  205. if (eyex<0.5) {
  206. #endif
  207. glPushMatrix();
  208. glTranslatef( 1.0, 1.5, 0.0 );
  209. glRotatef( w->spin, 1.0, 0.5, 0.0 );
  210. glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
  211. glCallList( w->objects_list[0] );
  212. glPopMatrix();
  213. glPushMatrix();
  214. glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 );
  215. glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
  216. glRotatef( w->spin, 1.0, 0.5, 0.0 );
  217. glScalef( 0.5, 0.5, 0.5 );
  218. glCallList( w->objects_list[1] );
  219. glPopMatrix();
  220. #ifndef USE_ZBUFFER
  221. }
  222. else {
  223. glPushMatrix();
  224. glTranslatef( -1.0, 0.85+3.0*fabs( cos(0.01*w->spin) ), 0.0 );
  225. glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
  226. glRotatef( w->spin, 1.0, 0.5, 0.0 );
  227. glScalef( 0.5, 0.5, 0.5 );
  228. glCallList( w->objects_list[1] );
  229. glPopMatrix();
  230. glPushMatrix();
  231. glTranslatef( 1.0, 1.5, 0.0 );
  232. glRotatef( w->spin, 1.0, 0.5, 0.0 );
  233. glRotatef( 0.5*w->spin, 0.0, 0.5, 1.0 );
  234. glCallList( w->objects_list[0] );
  235. glPopMatrix();
  236. }
  237. #endif
  238. }
  239. static void
  240. DrawTable(struct window *w)
  241. {
  242. glCallList(w->table_list);
  243. }
  244. static void
  245. DrawWindow(void)
  246. {
  247. struct window *w = CurrentWindow();
  248. static GLfloat light_pos[] = { 0.0, 20.0, 0.0, 1.0 };
  249. GLfloat dist = 20.0;
  250. GLfloat eyex, eyey, eyez;
  251. if (w->drawBuffer == GL_NONE) {
  252. glDrawBuffer(GL_BACK);
  253. glReadBuffer(GL_BACK);
  254. }
  255. else {
  256. glDrawBuffer(w->drawBuffer);
  257. glReadBuffer(w->drawBuffer);
  258. }
  259. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
  260. if (w->drawBuffer == GL_NONE) {
  261. glDrawBuffer(GL_NONE);
  262. }
  263. eyex = dist * cos(w->yrot * DEG2RAD) * cos(w->xrot * DEG2RAD);
  264. eyez = dist * sin(w->yrot * DEG2RAD) * cos(w->xrot * DEG2RAD);
  265. eyey = dist * sin(w->xrot * DEG2RAD);
  266. /* view from top */
  267. glPushMatrix();
  268. gluLookAt( eyex, eyey, eyez, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0 );
  269. glLightfv( GL_LIGHT0, GL_POSITION, light_pos );
  270. /* draw table into stencil planes */
  271. glDisable( GL_DEPTH_TEST );
  272. glEnable( GL_STENCIL_TEST );
  273. glStencilFunc( GL_ALWAYS, 1, 0xffffffff );
  274. glStencilOp( GL_REPLACE, GL_REPLACE, GL_REPLACE );
  275. glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
  276. DrawTable(w);
  277. glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
  278. glEnable( GL_DEPTH_TEST );
  279. /* render view from below (reflected viewport) */
  280. /* only draw where stencil==1 */
  281. if (eyey>0.0) {
  282. glPushMatrix();
  283. glStencilFunc( GL_EQUAL, 1, 0xffffffff ); /* draw if ==1 */
  284. glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
  285. glScalef( 1.0, -1.0, 1.0 );
  286. /* Reposition light in reflected space. */
  287. glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  288. DrawObjects(w, eyex, eyey, eyez);
  289. glPopMatrix();
  290. /* Restore light's original unreflected position. */
  291. glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
  292. }
  293. glDisable( GL_STENCIL_TEST );
  294. glEnable( GL_BLEND );
  295. glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  296. glEnable( GL_TEXTURE_2D );
  297. DrawTable(w);
  298. glDisable( GL_TEXTURE_2D );
  299. glDisable( GL_BLEND );
  300. /* view from top */
  301. glPushMatrix();
  302. DrawObjects(w, eyex, eyey, eyez);
  303. glPopMatrix();
  304. glPopMatrix();
  305. if (w->showBuffer == GL_DEPTH) {
  306. ShowDepthBuffer(w->width, w->height, 1.0, 0.0);
  307. }
  308. else if (w->showBuffer == GL_STENCIL) {
  309. ShowStencilBuffer(w->width, w->height, 255.0, 0.0);
  310. }
  311. else if (w->showBuffer == GL_ALPHA) {
  312. ShowAlphaBuffer(w->width, w->height);
  313. }
  314. if (w->drawBuffer == GL_FRONT)
  315. glFinish();
  316. else
  317. glutSwapBuffers();
  318. /* calc/show frame rate */
  319. {
  320. static GLint t0 = 0;
  321. static GLint frames = 0;
  322. GLint t = glutGet(GLUT_ELAPSED_TIME);
  323. frames++;
  324. if (t - t0 >= 5000) {
  325. GLfloat seconds = (t - t0) / 1000.0;
  326. GLfloat fps = frames / seconds;
  327. printf("%d frames in %g seconds = %g FPS\n", frames, seconds, fps);
  328. t0 = t;
  329. frames = 0;
  330. }
  331. }
  332. }
  333. static void
  334. Idle(void)
  335. {
  336. double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
  337. struct window *w;
  338. for (w = FirstWindow; w; w = w->next) {
  339. if (w->anim) {
  340. double dt;
  341. if (w->t0 < 0.0)
  342. w->t0 = t;
  343. dt = t - w->t0;
  344. w->t0 = t;
  345. w->spin += 60.0 * dt;
  346. w->yrot += 90.0 * dt;
  347. assert(w->id);
  348. glutSetWindow(w->id);
  349. glutPostRedisplay();
  350. }
  351. }
  352. }
  353. static void
  354. UpdateIdleFunc(void)
  355. {
  356. if (AnyAnimating())
  357. glutIdleFunc(Idle);
  358. else
  359. glutIdleFunc(NULL);
  360. }
  361. static void
  362. Key(unsigned char key, int x, int y)
  363. {
  364. struct window *w = CurrentWindow();
  365. (void) x;
  366. (void) y;
  367. switch (key) {
  368. case 'd':
  369. w->showBuffer = GL_DEPTH;
  370. glutPostRedisplay();
  371. break;
  372. case 's':
  373. w->showBuffer = GL_STENCIL;
  374. glutPostRedisplay();
  375. break;
  376. case 'a':
  377. w->showBuffer = GL_ALPHA;
  378. glutPostRedisplay();
  379. break;
  380. case 'c':
  381. w->showBuffer = GL_NONE;
  382. glutPostRedisplay();
  383. break;
  384. case 'f':
  385. if (w->drawBuffer == GL_FRONT)
  386. w->drawBuffer = GL_BACK;
  387. else
  388. w->drawBuffer = GL_FRONT;
  389. glutPostRedisplay();
  390. break;
  391. case '0':
  392. w->drawBuffer = GL_NONE;
  393. glutPostRedisplay();
  394. break;
  395. case ' ':
  396. w->anim = !w->anim;
  397. w->t0 = -1;
  398. UpdateIdleFunc();
  399. glutPostRedisplay();
  400. break;
  401. case 'n':
  402. CreateWindow();
  403. UpdateIdleFunc();
  404. break;
  405. case 'k':
  406. KillWindow(w);
  407. if (FirstWindow == NULL)
  408. exit(0);
  409. break;
  410. case 27:
  411. KillAllWindows();
  412. exit(0);
  413. break;
  414. default:
  415. ;
  416. }
  417. }
  418. static void
  419. SpecialKey(int key, int x, int y)
  420. {
  421. struct window *w = CurrentWindow();
  422. (void) x;
  423. (void) y;
  424. switch (key) {
  425. case GLUT_KEY_UP:
  426. w->xrot += 3.0;
  427. if (w->xrot > 85)
  428. w->xrot = 85;
  429. break;
  430. case GLUT_KEY_DOWN:
  431. w->xrot -= 3.0;
  432. if (w->xrot < 5)
  433. w->xrot = 5;
  434. break;
  435. case GLUT_KEY_LEFT:
  436. w->yrot += 3.0;
  437. break;
  438. case GLUT_KEY_RIGHT:
  439. w->yrot -= 3.0;
  440. break;
  441. }
  442. glutPostRedisplay();
  443. }
  444. static void
  445. CreateWindow(void)
  446. {
  447. char title[1000];
  448. struct window *w = (struct window *) calloc(1, sizeof(struct window));
  449. glutInitWindowSize(INIT_WIDTH, INIT_HEIGHT);
  450. w->id = glutCreateWindow("foo");
  451. sprintf(title, "reflect window %d", w->id);
  452. glutSetWindowTitle(title);
  453. assert(w->id);
  454. w->width = INIT_WIDTH;
  455. w->height = INIT_HEIGHT;
  456. w->anim = GL_TRUE;
  457. w->xrot = 30.0;
  458. w->yrot = 50.0;
  459. w->spin = 0.0;
  460. w->showBuffer = GL_NONE;
  461. w->drawBuffer = GL_BACK;
  462. InitWindow(w);
  463. glutReshapeFunc(Reshape);
  464. glutDisplayFunc(DrawWindow);
  465. glutKeyboardFunc(Key);
  466. glutSpecialFunc(SpecialKey);
  467. /* insert at head of list */
  468. w->next = FirstWindow;
  469. FirstWindow = w;
  470. }
  471. static void
  472. Usage(void)
  473. {
  474. printf("Keys:\n");
  475. printf(" a - show alpha buffer\n");
  476. printf(" d - show depth buffer\n");
  477. printf(" s - show stencil buffer\n");
  478. printf(" c - show color buffer\n");
  479. printf(" f - toggle rendering to front/back color buffer\n");
  480. printf(" n - create new window\n");
  481. printf(" k - kill window\n");
  482. printf(" SPACE - toggle animation\n");
  483. printf(" ARROWS - rotate scene\n");
  484. }
  485. int
  486. main(int argc, char *argv[])
  487. {
  488. glutInit(&argc, argv);
  489. glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH |
  490. GLUT_STENCIL | GLUT_ALPHA);
  491. CreateWindow();
  492. glutIdleFunc(Idle);
  493. Usage();
  494. glutMainLoop();
  495. return 0;
  496. }