spectral.c
上传用户:xk288cn
上传日期:2007-05-28
资源大小:4876k
文件大小:15k
- /* spectral.c - by Simon Hui, 3Dfx Interactive */
- /* make a noise texture from multiple frequencies of noise */
- #include <stdio.h>
- #include <stdlib.h>
- #include <math.h>
- #include <GL/glut.h>
- #if !defined(GL_VERSION_1_1) && !defined(GL_VERSION_1_2)
- #define glBindTexture glBindTextureEXT
- #endif
- static int texxsize = 256, texysize = 256;
- static int winxsize = 512, winysize = 512;
- /* the highest and lowest octaves in the final noise */
- static int minoctave = 1;
- static int maxoctave = 6;
- static GLenum ifmt = GL_LUMINANCE;
- /* texture object names */
- static GLuint basistex = 1;
- static GLuint noisetex = 2;
- static GLuint spectraltex = 6;
- static GLuint abstex = 7;
- int
- logOf(int n) {
- int i=0;
- for (i=-1; n > 0; i++) {
- n >>= 1;
- }
- return i;
- }
- void
- init_texture(void) {
- int i, j, n;
- int w, h;
- unsigned char *basis, *tex;
-
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- basis = (unsigned char *) malloc(texxsize * texysize);
- w = texxsize / 2;
- h = texysize / 2;
- for (j=0; j < h; j++) {
- for (i=0; i < w; i++) {
- GLint r;
- float u = i / (w - 1.0);
- float v = j / (h - 1.0);
- float f = 3 * u * u - 2 * u * u * u;
- float g = 3 * v * v - 2 * v * v * v;
-
- /* basis is a bicubic spline */
- r = f * g * 0xff;
- /* reflect around x and y axes */
- basis[j * texxsize + i] = r;
- basis[j * texxsize + texxsize-i-1] = r;
- basis[(texysize-j-1) * texxsize + i] = r;
- basis[(texysize-j-1) * texxsize + texxsize-i-1] = r;
- }
- }
- glBindTexture(GL_TEXTURE_2D, basistex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
- GL_RED, GL_UNSIGNED_BYTE, basis);
- free(basis);
- tex = (unsigned char *) malloc(4 * texxsize * texysize);
- for (n=0; n < 4; n++) {
- for (j=0; j < texysize; j++) {
- for (i=0; i < texxsize; i++) {
- int r = rand();
-
- /* mix it up a little more */
- r = ((r & 0xff) ^ ((r & 0xff00) >> 8)) & 0xff;
- /* For simplicity and because some opengl implementations offer */
- /* more texture color depth for luminance textures than rgb ones, */
- /* we use a luminance texture for the random noise. However, you */
- /* can make the texture rgb instead, and store different random */
- /* values for r, g, and b; this is especially useful if using */
- /* noise distortion below, because you'll get different distortion */
- /* values for s and t. */
- tex[j*texxsize + i] = r;
- }
- }
- glBindTexture(GL_TEXTURE_2D, noisetex + n);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, texxsize, texysize, 0,
- GL_RED, GL_UNSIGNED_BYTE, tex);
- }
- free(tex);
- }
- void
- init(void) {
- glClearColor(0.0, 0.0, 0.0, 1.0);
- glMatrixMode(GL_PROJECTION);
- glOrtho(0.0, 1.0, 0.0, 1.0, -1.0, 1.0);
- glMatrixMode(GL_MODELVIEW);
- glViewport(0, 0, winxsize, winysize);
- glDisable(GL_DITHER);
- init_texture();
- }
- void
- draw_basis(int tsize, int ssize, int xadj, int yadj) {
- float tilessize = 1.0 / ssize;
- float tiletsize = 1.0 / tsize;
- float xoff = (xadj - 0.5) * 0.5 * tilessize;
- float yoff = (yadj - 0.5) * 0.5 * tiletsize;
- float xo, yo;
- int i, j;
- glBindTexture(GL_TEXTURE_2D, basistex);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- /* draw as many copies of the basis function as needed for this frequency */
- for (j=0; j < tsize; j++) {
- for (i=0; i < ssize; i++) {
- xo = xoff + i * tilessize;
- yo = yoff + j * tiletsize;
- glBegin(GL_TRIANGLE_STRIP);
- glTexCoord2f(0.f, 0.f); glVertex2f(xo, yo);
- glTexCoord2f(0.f, 1.f); glVertex2f(xo, yo + tiletsize);
- glTexCoord2f(1.f, 0.f); glVertex2f(xo + tilessize, yo);
- glTexCoord2f(1.f, 1.f); glVertex2f(xo + tilessize, yo + tiletsize);
- glEnd();
- }
- }
- glFinish();
- }
- void
- draw_noise_texture(int tsize, int ssize, int xadj, int yadj, int texname) {
- float tilessize = 1.0 / ssize;
- float tiletsize = 1.0 / tsize;
- float xoff = (xadj - 0.5) * 0.5 * tilessize;
- float yoff = (yadj - 0.5) * 0.5 * tiletsize;
- float scale = 1.0 / (texxsize / ssize);
- glBindTexture(GL_TEXTURE_2D, texname);
- /* scale the texture matrix to get a noise pattern of desired frequency */
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glScalef(scale,scale,scale);
- glBegin(GL_TRIANGLE_STRIP);
- glTexCoord2f(0.f, 0.f); glVertex2f(xoff, yoff);
- glTexCoord2f(0.f, 1.f); glVertex2f(xoff, yoff + 1.0);
- glTexCoord2f(1.f, 0.f); glVertex2f(xoff + 1.0, yoff);
- glTexCoord2f(1.f, 1.f); glVertex2f(xoff + 1.0, yoff + 1.0);
- glEnd();
- glFlush();
- }
- static float wscale = 0.60;
- static unsigned int **octbufs, *spectralbuf, *absbuf;
- void
- make_octaves(void) {
- int w, h, i;
- int octaves = maxoctave - minoctave + 1;
- float weight, sumweight;
- glBlendFunc(GL_ZERO, GL_SRC_COLOR);
- glEnable(GL_TEXTURE_2D);
- /* find the total weight */
- weight = 1.0;
- sumweight = 0;
- for (i=0; i < octaves; i++) {
- sumweight += weight;
- weight *= wscale;
- }
- octbufs = (unsigned int **) malloc(octaves * sizeof(unsigned int *));
-
- weight = 1.0;
- w = h = (1 << minoctave);
- for (i=0; i < octaves; i++) {
- octbufs[i] = (unsigned int *) malloc(sizeof(unsigned int) *
- winxsize * winysize);
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_BLEND);
- draw_basis(w, h, 0, 0);
- glEnable(GL_BLEND);
- draw_noise_texture(w, h, 0, 0, noisetex);
- glAccum(GL_LOAD, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_BLEND);
- draw_basis(w, h, 1, 0);
- glEnable(GL_BLEND);
- draw_noise_texture(w, h, 1, 0, noisetex + 1);
- glAccum(GL_ACCUM, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_BLEND);
- draw_basis(w, h, 0, 1);
- glEnable(GL_BLEND);
- draw_noise_texture(w, h, 0, 1, noisetex + 2);
- glAccum(GL_ACCUM, 1.0);
- glClear(GL_COLOR_BUFFER_BIT);
- glDisable(GL_BLEND);
- draw_basis(w, h, 1, 1);
- glEnable(GL_BLEND);
- draw_noise_texture(w, h, 1, 1, noisetex + 3);
- glAccum(GL_ACCUM, 1.0);
- glDisable(GL_BLEND);
- glAccum(GL_RETURN, 1.0);
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- octbufs[i]);
- w <<= 1;
- h <<= 1;
- }
- glDisable(GL_TEXTURE_2D);
- }
- static GLboolean need_remake_octaves = GL_TRUE;
- static GLboolean need_remake_spectral = GL_TRUE;
- static GLboolean need_remake_abs_noise = GL_TRUE;
- void
- make_spectral_noise(void) {
- int i;
- int octaves = maxoctave - minoctave + 1;
- float weight, sumweight;
- if (need_remake_octaves) {
- make_octaves();
- need_remake_octaves = GL_FALSE;
- }
- /* find the total weight */
- weight = 1.0;
- sumweight = 0;
- for (i=0; i < octaves; i++) {
- sumweight += weight;
- weight *= wscale;
- }
- glClear(GL_COLOR_BUFFER_BIT | GL_ACCUM_BUFFER_BIT);
- weight = 1.0;
- for (i=0; i < octaves; i++) {
- glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) octbufs[i]);
- glAccum(GL_ACCUM, weight/sumweight);
- weight *= wscale;
- }
- /* save image in a texture */
- glAccum(GL_RETURN, 1.0);
- spectralbuf = (unsigned int *) malloc(4 * winxsize * winysize);
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- spectralbuf);
- glBindTexture(GL_TEXTURE_2D, spectraltex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, spectralbuf);
- }
- void
- make_abs_noise(void) {
- unsigned int *negbuf = (unsigned int *) malloc(4 * winxsize * winysize);
- unsigned int *posbuf = (unsigned int *) malloc(4 * winxsize * winysize);
- if (need_remake_spectral) {
- make_spectral_noise();
- need_remake_spectral = GL_FALSE;
- }
- glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) spectralbuf);
- glAccum(GL_LOAD, 1.0);
- /* make it signed */
- glAccum(GL_ADD, -0.5);
- /* get the positive part of the noise */
- glAccum(GL_RETURN, 2.0);
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) negbuf);
- /* invert the negative part of the noise */
- glAccum(GL_RETURN, -2.0);
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) posbuf);
- /* add positive and inverted negative together, and you get abs() */
- glClear(GL_COLOR_BUFFER_BIT);
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE);
- glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) posbuf);
- glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) negbuf);
- /* invert the colors so that peaks are bright instead of dark */
- glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ZERO);
- glColor4f(1,1,1,1);
- glBegin(GL_TRIANGLE_STRIP);
- glVertex2f(0,0);
- glVertex2f(0,1);
- glVertex2f(1,0);
- glVertex2f(1,1);
- glEnd();
- glDisable(GL_BLEND);
-
- free(posbuf);
- free(negbuf);
- /* save image in a texture */
- absbuf = (unsigned int *) malloc(4 * winxsize * winysize);
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) absbuf);
- glBindTexture(GL_TEXTURE_2D, abstex);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexImage2D(GL_TEXTURE_2D, 0, ifmt, winxsize, winysize, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, absbuf);
- }
- static GLboolean show_abs = GL_FALSE;
- static GLboolean show_distort = GL_FALSE;
- static GLboolean mapcolors = GL_FALSE;
- static float distfactor = 0.20;
- void
- display(void) {
- if (need_remake_spectral) {
- make_spectral_noise();
- need_remake_spectral = GL_FALSE;
- }
- if (show_abs) {
- if (need_remake_abs_noise) {
- make_abs_noise();
- need_remake_abs_noise = GL_FALSE;
- }
- glBindTexture(GL_TEXTURE_2D, abstex);
- } else {
- glBindTexture(GL_TEXTURE_2D, spectraltex);
- }
- glClear(GL_COLOR_BUFFER_BIT);
- glEnable(GL_TEXTURE_2D);
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- if (show_distort) {
- /* Use values in the spectral texture to distort the texture being */
- /* viewed, by jittering the texture coordinates. */
- float x, y0, y1;
- float s, t0, t1;
- float ds, dt;
- unsigned int pix0, pix1;
- int vrows = 64, vcols = 64;
- int i, j;
- for (j=0; j < (vrows - 1); j++) {
- t0 = y0 = j / (vrows - 1.0);
- t1 = y1 = (j + 1) / (vrows - 1.0);
- glBegin(GL_TRIANGLE_STRIP);
- for (i=0; i < vcols; i++) {
- s = x = i / (vcols - 1.0);
- pix0 = spectralbuf[j * winxsize + i];
- pix1 = spectralbuf[(j+1) * winxsize + i];
- /* Use green component of noise to distort S coord, */
- /* and blue component to distort T coord. Subtract */
- /* 127.5 to make it signed, and scale by distfactor.*/
- ds = ((pix0 & 0x00ff0000) >> 16);
- dt = ((pix0 & 0x0000ff00) >> 8);
- ds = (ds - 127.5) / 127.5 * distfactor;
- dt = (dt - 127.5) / 127.5 * distfactor;
- glTexCoord2f(s + ds, t0 + dt); glVertex2f(x, y0);
- ds = ((pix1 & 0x00ff0000) >> 16);
- dt = ((pix1 & 0x0000ff00) >> 8);
- ds = (ds - 127.5) / 127.5 * distfactor;
- dt = (dt - 127.5) / 127.5 * distfactor;
- glTexCoord2f(s + ds, t1 + dt); glVertex2f(x, y1);
- }
- glEnd();
- }
- } else {
- glBegin(GL_TRIANGLE_STRIP);
- glTexCoord2f(0, 0); glVertex2f(0, 0);
- glTexCoord2f(0, 1); glVertex2f(0, 1);
- glTexCoord2f(1, 0); glVertex2f(1, 0);
- glTexCoord2f(1, 1); glVertex2f(1, 1);
- glEnd();
- }
- glDisable(GL_TEXTURE_2D);
- if (mapcolors) {
- /* Map the gray values of the image into colors so that the texture */
- /* looks like flames. We do that by defining appropriate splines for */
- /* red, green, and blue. */
- float r, g, b;
- float rt = 0.8;
- float gt = 0.3;
- float bt = 0.1;
- int i, j;
- unsigned char *c;
- unsigned int *mapbuf = (unsigned int *) malloc(4 * winxsize * winysize);
-
- glReadPixels(0, 0, winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- mapbuf);
- for (j=0; j < winysize; j++) {
- for (i=0; i < winxsize; i++) {
- c = (unsigned char *) &mapbuf[j * winxsize + i];
- r = c[0] / 255.0;
- g = c[1] / 255.0;
- b = c[2] / 255.0;
- if (r < (1-rt)) {
- r = 0.0;
- } else {
- float k = (r - (1.0 - rt)) / rt;
- r = (3.0*k*k - 2.0*k*k*k) * 255.0;
- }
- if (g < (1-gt)) {
- g = 0.0;
- } else {
- float k = (g - (1.0 - gt)) / gt;
- g = (3.0*k*k - 2.0*k*k*k) * 255.0;
- }
- if (b < (1-bt)) {
- b = 0.0;
- } else {
- float k = (b - (1.0 - bt)) / bt;
- b = (3.0*k*k - 2.0*k*k*k) * 255.0;
- }
- c[0] = r;
- c[1] = g;
- c[2] = b;
- }
- }
- glDrawPixels(winxsize, winysize, GL_RGBA, GL_UNSIGNED_BYTE,
- (GLvoid *) mapbuf);
- free(mapbuf);
- }
- glFlush();
- }
- void
- reshape(int w, int h) {
- glViewport(0, 0, w, h);
- glutPostRedisplay();
- }
- enum {
- TOGGLE_ABS, TOGGLE_DISTORT, MORE_DISTORT, LESS_DISTORT, TOGGLE_MAP_COLORS,
- FIRE, QUIT
- };
- void
- menu(int value) {
- switch (value) {
- case TOGGLE_ABS:
- show_abs = !show_abs;
- break;
- case TOGGLE_DISTORT:
- show_distort = !show_distort;
- break;
- case MORE_DISTORT:
- if (distfactor > 0.05) distfactor -= 0.05;
- break;
- case LESS_DISTORT:
- if (distfactor < 1.00) distfactor += 0.05;
- break;
- case TOGGLE_MAP_COLORS:
- mapcolors = !mapcolors;
- break;
- case FIRE:
- mapcolors = GL_TRUE;
- show_distort = GL_TRUE;
- show_abs = GL_TRUE;
- break;
- case QUIT:
- exit(0);
- }
- glutPostRedisplay();
- }
- int
- main(int argc, char** argv) {
- glutInit(&argc, argv);
- glutInitWindowSize(winxsize, winysize);
- glutInitDisplayMode(GLUT_RGBA | GLUT_ACCUM);
- (void)glutCreateWindow("spectral noise function");
- init();
- glutDisplayFunc(display);
- glutReshapeFunc(reshape);
- glutCreateMenu(menu);
- glutAddMenuEntry("Toggle Absolute Value", TOGGLE_ABS);
- glutAddMenuEntry("Toggle Noise Distortion", TOGGLE_DISTORT);
- glutAddMenuEntry("Decrease Distortion", MORE_DISTORT);
- glutAddMenuEntry("Increase Distortion", LESS_DISTORT);
- glutAddMenuEntry("Toggle Color Mapping", TOGGLE_MAP_COLORS);
- glutAddMenuEntry("Simulation of Fire", FIRE);
- glutAddMenuEntry("Quit", QUIT);
- glutAttachMenu(GLUT_RIGHT_BUTTON);
- glutMainLoop();
- return 0; /* ANSI C requires main to return int. */
- }