📄 underwater.c
字号:
void reshape(int w, int h)
{
glViewport(0, 0, (GLsizei) w, (GLsizei) h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(40.0, /* field of view in degree */
(GLfloat) w/(GLfloat) h, /* aspect ratio */
20.0, /* Z near */
100.0); /* Z far */
glMatrixMode(GL_MODELVIEW);
}
void
idle(void)
{
/* Advance the caustic pattern. */
currentCaustic = (currentCaustic + causticIncrement) % NUM_PATTERNS;
glutPostRedisplay();
}
void
updateIdleFunc(void)
{
/* Must be both displaying the caustic patterns and have the
caustics in rippling motion to need an idle callback. */
if (showCaustics && causticMotion) {
glutIdleFunc(idle);
} else {
glutIdleFunc(NULL);
}
}
void
visible(int vis)
{
/* Stop the animation when the window is not visible. */
if (vis == GLUT_VISIBLE)
updateIdleFunc();
else
glutIdleFunc(NULL);
}
/* ARGSUSED2 */
static void
mouse(int button, int state, int x, int y)
{
/* Rotate the scene with the left mouse button. */
if (button == GLUT_LEFT_BUTTON) {
if (state == GLUT_DOWN) {
moving = 1;
startx = x;
starty = y;
}
if (state == GLUT_UP) {
moving = 0;
}
}
/* Rotate the light position with the middle mouse button. */
if (button == GLUT_MIDDLE_BUTTON) {
if (state == GLUT_DOWN) {
lightMoving = 1;
lightStartX = x;
lightStartY = y;
}
if (state == GLUT_UP) {
lightMoving = 0;
}
}
}
/* ARGSUSED1 */
static void
motion(int x, int y)
{
if (moving) {
angle = angle + (x - startx);
angle2 = angle2 + (y - starty);
startx = x;
starty = y;
glutPostRedisplay();
}
if (lightMoving) {
lightAngle += (x - lightStartX)/40.0;
lightHeight += (lightStartY - y)/20.0;
lightStartX = x;
lightStartY = y;
glutPostRedisplay();
}
}
/* ARGSUSED1 */
static void
keyboard(unsigned char c, int x, int y)
{
switch (c) {
case 27: /* Escape quits. */
exit(0);
break;
case 'R': /* Simplistic benchmarking. */
case 'r':
reportSpeed = !reportSpeed;
break;
case ' ': /* Spacebar toggles caustic rippling motion. */
causticMotion = !causticMotion;
updateIdleFunc();
break;
}
}
void
menuSelect(int value)
{
switch (value) {
case M_POSITIONAL:
directionalLight = 0;
break;
case M_DIRECTIONAL:
directionalLight = 1;
break;
case M_GREENISH_LIGHT:
lightDiffuseColor[0] = 1.0;
lightDiffuseColor[1] = 1.5; /* XXX Green = 1.5 */
lightDiffuseColor[2] = 1.0;
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuseColor);
break;
case M_WHITE_LIGHT:
lightDiffuseColor[0] = 1.5; /* XXX Red = 1.5 */
lightDiffuseColor[1] = 1.5; /* XXX Green = 1.5 */
lightDiffuseColor[2] = 1.5; /* XXX Blue = 1.5 */
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuseColor);
break;
case M_WITH_CAUSTICS:
showCaustics = 1;
updateIdleFunc();
break;
case M_NO_CAUSTICS:
showCaustics = 0;
updateIdleFunc();
break;
case M_SWITCH_MODEL:
object = (object + 1) % 3;
break;
case M_INCREASE_RIPPLE_SIZE:
causticScale /= 1.5;
break;
case M_DECREASE_RIPPLE_SIZE:
causticScale *= 1.5;
break;
}
glutPostRedisplay();
}
int
main(int argc, char **argv)
{
int width, height;
int i;
GLubyte *imageData;
glutInit(&argc, argv);
for (i=1; i<argc; i++) {
if (!strcmp("-lesstex", argv[i])) {
/* Only use 16 caustic textures. Saves texture memory and works
better on slow machines. */
causticIncrement = 2;
} else if (!strcmp("-evenlesstex", argv[i])) {
/* Only use 8 caustic textures. Saves even more texture memory for
slow machines. Temporal rippling suffers. */
causticIncrement = 4;
} else if (!strcmp("-nomipmap", argv[i])) {
/* Don't use linear mipmap linear texture filtering; instead
use linear filtering. */
useMipmaps = 0;
} else if (!strcmp("-fullscreen", argv[i])) {
fullscreen = 1;
} else {
fprintf(stderr, "usage: caustics [-lesstex]\n");
fprintf(stderr, " -lesstex uses half the caustic textures.\n");
fprintf(stderr, " -evenlesstex uses one fourth of the caustic textures.\n");
exit(1);
}
}
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
if (fullscreen) {
glutGameModeString("800x600:16@60");
glutEnterGameMode();
} else {
glutCreateWindow("underwater");
}
/* Check that renderer has the GL_EXT_texture_object
extension or supports OpenGL 1.1 */
#ifdef TEXTURE_OBJECT
{
char *version = (char *) glGetString(GL_VERSION);
if (glutExtensionSupported("GL_EXT_texture_object")
|| strncmp(version, "1.1", 3) == 0) {
HaveTexObj = GL_TRUE;
}
}
#endif
glEnable(GL_TEXTURE_2D);
#ifdef TEXTURE_OBJECT /* Replace texture environment not in OpenGL 1.0. */
if (HaveTexObj)
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
#endif
/* Load the caustic ripple textures. */
printf("loading caustics:");
for (i=0; i<NUM_PATTERNS; i += causticIncrement) {
char filename[80];
sprintf(filename, "caust%02d.bw", i);
printf(" %d", i);
fflush(stdout);
imageData = read_alpha_texture(filename, &width, &height);
if (imageData == NULL) {
fprintf(stderr, "\n%s: could not load image file\n", filename);
exit(1);
}
if (HaveTexObj)
glBindTexture(GL_TEXTURE_2D, i+1);
else
glNewList(i+101, GL_COMPILE);
if (useMipmaps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_LUMINANCE, width, height,
GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, height, width, 0,
GL_LUMINANCE, GL_UNSIGNED_BYTE, imageData);
}
free(imageData);
if (!HaveTexObj)
glEndList();
}
printf(".\n");
/* Load an RGB file for the floor texture. */
printf("loading RGB textures: floor");
fflush(stdout);
imageData = read_rgb_texture(FLOOR_FILE, &width, &height);
if (imageData == NULL) {
fprintf(stderr, "%s: could not load image file\n", FLOOR_FILE);
exit(1);
}
printf(".\n");
if (HaveTexObj)
glBindTexture(GL_TEXTURE_2D, 100);
else
glNewList(100, GL_COMPILE);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
if (useMipmaps) {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height, GL_RGB,
GL_UNSIGNED_BYTE, imageData);
} else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, imageData);
}
free(imageData);
if (!HaveTexObj)
glEndList();
glMatrixMode(GL_MODELVIEW);
gluLookAt(0.0, 8.0, 60.0, /* eye is at (0,8,60) */
0.0, 8.0, 0.0, /* center is at (0,8,0) */
0.0, 1.0, 0.); /* up is in postivie Y direction */
/* Setup initial OpenGL rendering state. */
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuseColor);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
/* Register assorted GLUT callback routines. */
glutDisplayFunc(display);
glutReshapeFunc(reshape);
glutVisibilityFunc(visible);
glutMouseFunc(mouse);
glutMotionFunc(motion);
glutKeyboardFunc(keyboard);
/* Create a pop-up menu. */
if (!fullscreen) {
glutCreateMenu(menuSelect);
glutAddMenuEntry("Positional light", M_POSITIONAL);
glutAddMenuEntry("Directional light", M_DIRECTIONAL);
glutAddMenuEntry("Greenish light", M_GREENISH_LIGHT);
glutAddMenuEntry("White light", M_WHITE_LIGHT);
glutAddMenuEntry("With caustics", M_WITH_CAUSTICS);
glutAddMenuEntry("No caustics", M_NO_CAUSTICS);
glutAddMenuEntry("Switch model", M_SWITCH_MODEL);
glutAddMenuEntry("Increase ripple size", M_INCREASE_RIPPLE_SIZE);
glutAddMenuEntry("Decrease ripple size", M_DECREASE_RIPPLE_SIZE);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
/* For rendering the MODEL_DINO object. */
dinoDisplayList = makeDinosaur();
/* Enter GLUT's main loop; callback dispatching begins. */
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -