spectral.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:15k
源码类别:

GIS编程

开发平台:

Visual C++

  1. /* spectral.c - by Simon Hui, 3Dfx Interactive */
  2. /* make a noise texture from multiple frequencies of noise */
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <math.h>
  6. #include <GL/glut.h>
  7. #if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2)
  8. #define glBindTexture glBindTextureEXT
  9. #endif
  10. static int texxsize = 256, texysize = 256;
  11. static int winxsize = 512, winysize = 512;
  12. /* the highest and lowest octaves in the final noise */
  13. static int minoctave = 1;
  14. static int maxoctave = 6;
  15. static GLenum ifmt = GL_LUMINANCE;
  16. /* texture object names */
  17. static GLuint basistex = 1;
  18. static GLuint noisetex = 2;
  19. static GLuint spectraltex = 6;
  20. static GLuint abstex = 7;
  21. int
  22. logOf(int n) {
  23.   int i=0;
  24.   for (i=-1; n > 0; i++) {
  25.     n >>= 1;
  26.   }
  27.   return i;
  28. }
  29. void
  30. init_texture(void) {
  31.   int i, j, n;
  32.   int w, h;
  33.   unsigned char *basis, *tex;
  34.   
  35.   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  36.   basis = (unsigned char *) malloc(texxsize * texysize);
  37.   w = texxsize / 2;
  38.   h = texysize / 2;
  39.   for (j=0; j < h; j++) {
  40.     for (i=0; i < w; i++) {
  41.       GLint r;
  42.       float u = i / (w - 1.0);
  43.       float v = j / (h - 1.0);
  44.       float f = 3 * u * u - 2 * u * u * u;
  45.       float g = 3 * v * v - 2 * v * v * v;
  46.       
  47.       /* basis is a bicubic spline */
  48.       r = f * g * 0xff;
  49.       /* reflect around x and y axes */
  50.       basis[j * texxsize + i] = r;
  51.       basis[j * texxsize + texxsize-i-1] = r;
  52.       basis[(texysize-j-1) * texxsize + i] = r;
  53.       basis[(texysize-j-1) * texxsize + texxsize-i-1] = r;
  54.     }
  55.   }
  56.   glBindTexture(GL_TEXTURE_2D, basistex);
  57.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  58.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  59.   glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
  60.        GL_RED, GL_UNSIGNED_BYTE, basis);
  61.   free(basis);
  62.   tex = (unsigned char *) malloc(4 * texxsize * texysize);
  63.   for (n=0; n < 4; n++) {
  64.     for (j=0; j < texysize; j++) {
  65.       for (i=0; i < texxsize; i++) {
  66. int r = rand();
  67. /* mix it up a little more */
  68. r = ((r & 0xff) ^ ((r & 0xff00) >> 8)) & 0xff;
  69. /* For simplicity and because some opengl implementations offer    */
  70. /* more texture color depth for luminance textures than rgb ones,  */
  71. /* we use a luminance texture for the random noise.  However, you  */
  72. /* can make the texture rgb instead, and store different random    */
  73. /* values for r, g, and b; this is especially useful if using      */
  74. /* noise distortion below, because you'll get different distortion */
  75. /* values for s and t.                                             */
  76. tex[j*texxsize + i] = r;
  77.       }
  78.     }
  79.     glBindTexture(GL_TEXTURE_2D, noisetex + n);
  80.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  81.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  82.     glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
  83.  GL_RED, GL_UNSIGNED_BYTE, tex);
  84.   }
  85.   free(tex);
  86. }
  87. void
  88. init(void) {
  89.   glClearColor(0.0, 0.0, 0.0, 1.0);
  90.   glMatrixMode(GL_PROJECTION);
  91.   glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
  92.   glMatrixMode(GL_MODELVIEW);
  93.   glViewport(0, 0, winxsize, winysize);
  94.   glDisable(GL_DITHER);
  95.   init_texture();
  96. }
  97. void
  98. draw_basis(int tsize, int ssize, int xadj, int yadj) {
  99.   float tilessize = 1.0 / ssize;
  100.   float tiletsize = 1.0 / tsize;
  101.   float xoff = (xadj - 0.5) * 0.5 * tilessize;
  102.   float yoff = (yadj - 0.5) * 0.5 * tiletsize;
  103.   float xo, yo;
  104.   int i, j;
  105.   glBindTexture(GL_TEXTURE_2D, basistex);
  106.   glMatrixMode(GL_TEXTURE);
  107.   glLoadIdentity();
  108.   /* draw as many copies of the basis function as needed for this frequency */
  109.   for (j=0; j < tsize; j++) {
  110.     for (i=0; i < ssize; i++) {
  111.       xo = xoff + i * tilessize;
  112.       yo = yoff + j * tiletsize;
  113.       glBegin(GL_TRIANGLE_STRIP);
  114.       glTexCoord2f(0.f, 0.f); glVertex2f(xo, yo); 
  115.       glTexCoord2f(0.f, 1.f); glVertex2f(xo, yo + tiletsize); 
  116.       glTexCoord2f(1.f, 0.f); glVertex2f(xo + tilessize, yo); 
  117.       glTexCoord2f(1.f, 1.f); glVertex2f(xo + tilessize, yo + tiletsize); 
  118.       glEnd();
  119.     }
  120.   }
  121.   glFinish();
  122. }
  123. void
  124. draw_noise_texture(int tsize, int ssize, int xadj, int yadj, int texname) {
  125.   float tilessize = 1.0 / ssize;
  126.   float tiletsize = 1.0 / tsize;
  127.   float xoff = (xadj - 0.5) * 0.5 * tilessize;
  128.   float yoff = (yadj - 0.5) * 0.5 * tiletsize;
  129.   float scale = 1.0 / (texxsize / ssize);
  130.   glBindTexture(GL_TEXTURE_2D, texname);
  131.   /* scale the texture matrix to get a noise pattern of desired frequency */
  132.   glMatrixMode(GL_TEXTURE);
  133.   glLoadIdentity();
  134.   glScalef(scale,scale,scale);
  135.   glBegin(GL_TRIANGLE_STRIP);
  136.   glTexCoord2f(0.f, 0.f); glVertex2f(xoff, yoff); 
  137.   glTexCoord2f(0.f, 1.f); glVertex2f(xoff, yoff + 1.0); 
  138.   glTexCoord2f(1.f, 0.f); glVertex2f(xoff + 1.0, yoff); 
  139.   glTexCoord2f(1.f, 1.f); glVertex2f(xoff + 1.0, yoff + 1.0); 
  140.   glEnd();
  141.   glFlush();
  142. }
  143. static float wscale = 0.60;
  144. static unsigned int **octbufs, *spectralbuf, *absbuf;
  145. void
  146. make_octaves(void) {
  147.   int w, h, i;
  148.   int octaves = maxoctave - minoctave + 1;
  149.   float weight, sumweight;
  150.   glBlendFunc(GL_ZERO, GL_SRC_COLOR);
  151.   glEnable(GL_TEXTURE_2D);
  152.   /* find the total weight */
  153.   weight = 1.0;
  154.   sumweight = 0;
  155.   for (i=0; i < octaves; i++) {
  156.     sumweight += weight;
  157.     weight *= wscale;
  158.   }
  159.   octbufs = (unsigned int **) malloc(octaves * sizeof(unsigned int *));
  160.   
  161.   weight = 1.0;
  162.   w = h = (1 << minoctave);
  163.   for (i=0; i < octaves; i++) {
  164.     octbufs[i] = (unsigned int *) malloc(sizeof(unsigned int) * 
  165.  winxsize * winysize);
  166.     glClear(GL_COLOR_BUFFER_BIT);
  167.     glDisable(GL_BLEND);
  168.     draw_basis(w, h, 0, 0);
  169.     glEnable(GL_BLEND);
  170.     draw_noise_texture(w, h, 0, 0, noisetex);
  171.     glAccum(GL_LOAD, 1.0);
  172.     glClear(GL_COLOR_BUFFER_BIT);
  173.     glDisable(GL_BLEND);
  174.     draw_basis(w, h, 1, 0);
  175.     glEnable(GL_BLEND);
  176.     draw_noise_texture(w, h, 1, 0, noisetex + 1);
  177.     glAccum(GL_ACCUM, 1.0);
  178.     glClear(GL_COLOR_BUFFER_BIT);
  179.     glDisable(GL_BLEND);
  180.     draw_basis(w, h, 0, 1);
  181.     glEnable(GL_BLEND);
  182.     draw_noise_texture(w, h, 0, 1, noisetex + 2);
  183.     glAccum(GL_ACCUM, 1.0);
  184.     glClear(GL_COLOR_BUFFER_BIT);
  185.     glDisable(GL_BLEND);
  186.     draw_basis(w, h, 1, 1);
  187.     glEnable(GL_BLEND);
  188.     draw_noise_texture(w, h, 1, 1, noisetex + 3);
  189.     glAccum(GL_ACCUM, 1.0);
  190.     glDisable(GL_BLEND);
  191.     glAccum(GL_RETURN, 1.0);
  192.     glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  193.  octbufs[i]);
  194.     w <<= 1;
  195.     h <<= 1;
  196.   }
  197.   glDisable(GL_TEXTURE_2D);
  198. }
  199. static GLboolean need_remake_octaves = GL_TRUE;
  200. static GLboolean need_remake_spectral = GL_TRUE;
  201. static GLboolean need_remake_abs_noise = GL_TRUE;
  202. void
  203. make_spectral_noise(void) {
  204.   int i;
  205.   int octaves = maxoctave - minoctave + 1;
  206.   float weight, sumweight;
  207.   if (need_remake_octaves) {
  208.     make_octaves();
  209.     need_remake_octaves = GL_FALSE;
  210.   }
  211.   /* find the total weight */
  212.   weight = 1.0;
  213.   sumweight = 0;
  214.   for (i=0; i < octaves; i++) {
  215.     sumweight += weight;
  216.     weight *= wscale;
  217.   }
  218.   glClear(GL_COLOR_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
  219.   weight = 1.0;
  220.   for (i=0; i < octaves; i++) {
  221.     glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  222.  (GLvoid *) octbufs[i]);
  223.     glAccum(GL_ACCUM, weight/sumweight);
  224.     weight *= wscale;
  225.   }
  226.   /* save image in a texture */
  227.   glAccum(GL_RETURN, 1.0);
  228.   spectralbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  229.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  230.        spectralbuf);
  231.   glBindTexture(GL_TEXTURE_2D, spectraltex);
  232.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  233.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  234.   glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
  235.        GL_RGBA, GL_UNSIGNED_BYTE, spectralbuf);
  236. }
  237. void
  238. make_abs_noise(void) {
  239.   unsigned int *negbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  240.   unsigned int *posbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  241.   if (need_remake_spectral) {
  242.     make_spectral_noise();
  243.     need_remake_spectral = GL_FALSE;
  244.   }
  245.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  246.        (GLvoid *) spectralbuf);
  247.   glAccum(GL_LOAD, 1.0);
  248.   /* make it signed */
  249.   glAccum(GL_ADD, -0.5);
  250.   /* get the positive part of the noise */
  251.   glAccum(GL_RETURN, 2.0);
  252.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  253.        (GLvoid *) negbuf);
  254.   /* invert the negative part of the noise */
  255.   glAccum(GL_RETURN, -2.0);
  256.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  257.        (GLvoid *) posbuf);
  258.   /* add positive and inverted negative together, and you get abs() */
  259.   glClear(GL_COLOR_BUFFER_BIT);
  260.   glEnable(GL_BLEND);
  261.   glBlendFunc(GL_ONE, GL_ONE);
  262.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  263.        (GLvoid *) posbuf);
  264.   glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE, 
  265.        (GLvoid *) negbuf);
  266.   /* invert the colors so that peaks are bright instead of dark */
  267.   glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
  268.   glColor4f(1,1,1,1);
  269.   glBegin(GL_TRIANGLE_STRIP);
  270.   glVertex2f(0,0);
  271.   glVertex2f(0,1);
  272.   glVertex2f(1,0);
  273.   glVertex2f(1,1);
  274.   glEnd();
  275.   glDisable(GL_BLEND);
  276.   
  277.   free(posbuf);
  278.   free(negbuf);
  279.   /* save image in a texture */
  280.   absbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  281.   glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  282.        (GLvoid *) absbuf);
  283.   glBindTexture(GL_TEXTURE_2D, abstex);
  284.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  285.   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  286.   glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
  287.        GL_RGBA, GL_UNSIGNED_BYTE, absbuf);
  288. }
  289. static GLboolean show_abs = GL_FALSE;
  290. static GLboolean show_distort = GL_FALSE;
  291. static GLboolean mapcolors = GL_FALSE;
  292. static float distfactor = 0.20;
  293. void
  294. display(void) {
  295.   if (need_remake_spectral) {
  296.     make_spectral_noise();
  297.     need_remake_spectral = GL_FALSE;
  298.   }
  299.   if (show_abs) {
  300.     if (need_remake_abs_noise) {
  301.       make_abs_noise();
  302.       need_remake_abs_noise = GL_FALSE;
  303.     }
  304.     glBindTexture(GL_TEXTURE_2D, abstex);
  305.   } else {
  306.     glBindTexture(GL_TEXTURE_2D, spectraltex);
  307.   }
  308.   glClear(GL_COLOR_BUFFER_BIT);
  309.   glEnable(GL_TEXTURE_2D);
  310.   glMatrixMode(GL_TEXTURE);
  311.   glLoadIdentity();
  312.   if (show_distort) {
  313.     /* Use values in the spectral texture to distort the texture being */
  314.     /* viewed, by jittering the texture coordinates.                   */
  315.     float x, y0, y1;
  316.     float s, t0, t1;
  317.     float ds, dt;
  318.     unsigned int pix0, pix1;
  319.     int vrows = 64, vcols = 64;
  320.     int i, j;
  321.     for (j=0; j < (vrows - 1); j++) {
  322.       t0 = y0 = j / (vrows - 1.0);
  323.       t1 = y1 = (j + 1) / (vrows - 1.0);
  324.       glBegin(GL_TRIANGLE_STRIP);
  325.       for (i=0; i < vcols; i++) {
  326. s = x = i / (vcols - 1.0);
  327. pix0 = spectralbuf[j * winxsize + i];
  328. pix1 = spectralbuf[(j+1) * winxsize + i];
  329. /* Use green component of noise to distort S coord, */
  330. /* and blue component to distort T coord.  Subtract */
  331. /* 127.5 to make it signed, and scale by distfactor.*/
  332. ds = ((pix0 & 0x00ff0000) >> 16);
  333. dt = ((pix0 & 0x0000ff00) >>  8);
  334. ds = (ds - 127.5) / 127.5 * distfactor;
  335. dt = (dt - 127.5) / 127.5 * distfactor;
  336. glTexCoord2f(s + ds, t0 + dt); glVertex2f(x, y0);
  337. ds = ((pix1 & 0x00ff0000) >> 16);
  338. dt = ((pix1 & 0x0000ff00) >>  8);
  339. ds = (ds - 127.5) / 127.5 * distfactor;
  340. dt = (dt - 127.5) / 127.5 * distfactor;
  341. glTexCoord2f(s + ds, t1 + dt); glVertex2f(x, y1);
  342.       }
  343.       glEnd();
  344.     }
  345.   } else {
  346.     glBegin(GL_TRIANGLE_STRIP);
  347.     glTexCoord2f(0, 0); glVertex2f(0, 0);
  348.     glTexCoord2f(0, 1); glVertex2f(0, 1);
  349.     glTexCoord2f(1, 0); glVertex2f(1, 0);
  350.     glTexCoord2f(1, 1); glVertex2f(1, 1);
  351.     glEnd();
  352.   }
  353.   glDisable(GL_TEXTURE_2D);
  354.   if (mapcolors) {
  355.     /* Map the gray values of the image into colors so that the texture   */
  356.     /* looks like flames.  We do that by defining appropriate splines for */
  357.     /* red, green, and blue.                                              */
  358.     float r, g, b;
  359.     float rt = 0.8;
  360.     float gt = 0.3;
  361.     float bt = 0.1;
  362.     int i, j;
  363.     unsigned char *c;
  364.     unsigned int *mapbuf = (unsigned int *) malloc(4 * winxsize * winysize);
  365.       
  366.     glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  367.  mapbuf);
  368.     for (j=0; j < winysize; j++) {
  369.       for (i=0; i < winxsize; i++) {
  370. c = (unsigned char *) &mapbuf[j * winxsize + i];
  371. r = c[0] / 255.0;
  372. g = c[1] / 255.0;
  373. b = c[2] / 255.0;
  374. if (r < (1-rt)) {
  375.   r = 0.0;
  376. } else {
  377.   float k = (r - (1.0 - rt)) / rt;
  378.   r = (3.0*k*k - 2.0*k*k*k) * 255.0;
  379. }
  380. if (g < (1-gt)) {
  381.   g = 0.0;
  382. } else {
  383.   float k = (g - (1.0 - gt)) / gt;
  384.   g = (3.0*k*k - 2.0*k*k*k) * 255.0;
  385. }
  386. if (b < (1-bt)) {
  387.   b = 0.0;
  388. } else {
  389.   float k = (b - (1.0 - bt)) / bt;
  390.   b = (3.0*k*k - 2.0*k*k*k) * 255.0;
  391. }
  392. c[0] = r;
  393. c[1] = g;
  394. c[2] = b;
  395.       }
  396.     }
  397.     glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
  398.  (GLvoid *) mapbuf);
  399.     free(mapbuf);
  400.   }
  401.   glFlush();
  402. }
  403. void
  404. reshape(int w, int h) {
  405.   glViewport(0, 0, w, h);
  406.   glutPostRedisplay();
  407. }
  408. enum {
  409.   TOGGLE_ABS, TOGGLE_DISTORT, MORE_DISTORT, LESS_DISTORT, TOGGLE_MAP_COLORS,
  410.   FIRE, QUIT
  411. };
  412. void
  413. menu(int value) {
  414.   switch (value) {
  415.   case TOGGLE_ABS:
  416.     show_abs = !show_abs;
  417.     break;
  418.   case TOGGLE_DISTORT:
  419.     show_distort = !show_distort;
  420.     break;
  421.   case MORE_DISTORT:
  422.     if (distfactor > 0.05) distfactor -= 0.05;
  423.     break;
  424.   case LESS_DISTORT:
  425.     if (distfactor < 1.00) distfactor += 0.05;
  426.     break;
  427.   case TOGGLE_MAP_COLORS:
  428.     mapcolors = !mapcolors;
  429.     break;
  430.   case FIRE:
  431.     mapcolors = GL_TRUE;
  432.     show_distort = GL_TRUE;
  433.     show_abs = GL_TRUE;
  434.     break;
  435.   case QUIT:
  436.     exit(0);
  437.   }
  438.   glutPostRedisplay();
  439. }
  440. int
  441. main(int argc, char** argv) {
  442.   glutInit(&argc, argv);
  443.   glutInitWindowSize(winxsize, winysize);
  444.   glutInitDisplayMode(GLUT_RGBA | GLUT_ACCUM);
  445.   (void)glutCreateWindow("spectral noise function");
  446.   init();
  447.   glutDisplayFunc(display);
  448.   glutReshapeFunc(reshape);
  449.   glutCreateMenu(menu);
  450.   glutAddMenuEntry("Toggle Absolute Value", TOGGLE_ABS);
  451.   glutAddMenuEntry("Toggle Noise Distortion", TOGGLE_DISTORT);
  452.   glutAddMenuEntry("Decrease Distortion", MORE_DISTORT);
  453.   glutAddMenuEntry("Increase Distortion", LESS_DISTORT);
  454.   glutAddMenuEntry("Toggle Color Mapping", TOGGLE_MAP_COLORS);
  455.   glutAddMenuEntry("Simulation of Fire", FIRE);
  456.   glutAddMenuEntry("Quit", QUIT);
  457.   glutAttachMenu(GLUT_RIGHT_BUTTON);
  458.   glutMainLoop();
  459.   return 0;             /* ANSI C requires main to return int. */
  460. }