+/* ARGSUSED2 */\r
+static void\r
+mouse(int button, int state, int x, int y)\r
+{\r
+ if (button == GLUT_LEFT_BUTTON) {\r
+ if (state == GLUT_DOWN) {\r
+ moving = 1;\r
+ startx = x;\r
+ starty = y;\r
+ }\r
+ if (state == GLUT_UP) {\r
+ moving = 0;\r
+ }\r
+ }\r
+ if (button == GLUT_MIDDLE_BUTTON) {\r
+ if (state == GLUT_DOWN) {\r
+ lightMoving = 1;\r
+ lightStartX = x;\r
+ lightStartY = y;\r
+ }\r
+ if (state == GLUT_UP) {\r
+ lightMoving = 0;\r
+ }\r
+ }\r
+}\r
+\r
+/* ARGSUSED1 */\r
+static void\r
+motion(int x, int y)\r
+{\r
+ if (moving) {\r
+ angle = angle + (x - startx);\r
+ angle2 = angle2 + (y - starty);\r
+ startx = x;\r
+ starty = y;\r
+ glutPostRedisplay();\r
+ }\r
+ if (lightMoving) {\r
+ lightAngle += (x - lightStartX)/40.0;\r
+ lightHeight += (lightStartY - y)/20.0;\r
+ lightStartX = x;\r
+ lightStartY = y;\r
+ glutPostRedisplay();\r
+ }\r
+}\r
+\r
+/* Advance time varying state when idle callback registered. */\r
+static void\r
+idle(void)\r
+{\r
+ static float time = 0.0;\r
+\r
+ time = glutGet(GLUT_ELAPSED_TIME) / 500.0;\r
+\r
+ jump = 4.0 * fabs(sin(time)*0.5);\r
+ if (!lightMoving) {\r
+ lightAngle += 0.03;\r
+ }\r
+ glutPostRedisplay();\r
+}\r
+\r
+enum {\r
+ M_NONE, M_MOTION, M_LIGHT, M_TEXTURE, M_SHADOWS, M_REFLECTION, M_DINOSAUR,\r
+ M_STENCIL_REFLECTION, M_STENCIL_SHADOW, M_OFFSET_SHADOW,\r
+ M_POSITIONAL, M_DIRECTIONAL, M_PERFORMANCE\r
+};\r
+\r
+static void\r
+controlLights(int value)\r
+{\r
+ switch (value) {\r
+ case M_NONE:\r
+ return;\r
+ case M_MOTION:\r
+ animation = 1 - animation;\r
+ if (animation) {\r
+ glutIdleFunc(idle);\r
+ } else {\r
+ glutIdleFunc(NULL);\r
+ }\r
+ break;\r
+ case M_LIGHT:\r
+ lightSwitch = !lightSwitch;\r
+ if (lightSwitch) {\r
+ glEnable(GL_LIGHT0);\r
+ } else {\r
+ glDisable(GL_LIGHT0);\r
+ }\r
+ break;\r
+ case M_TEXTURE:\r
+ useTexture = !useTexture;\r
+ break;\r
+ case M_SHADOWS:\r
+ renderShadow = 1 - renderShadow;\r
+ break;\r
+ case M_REFLECTION:\r
+ renderReflection = 1 - renderReflection;\r
+ break;\r
+ case M_DINOSAUR:\r
+ renderDinosaur = 1 - renderDinosaur;\r
+ break;\r
+ case M_STENCIL_REFLECTION:\r
+ stencilReflection = 1 - stencilReflection;\r
+ break;\r
+ case M_STENCIL_SHADOW:\r
+ stencilShadow = 1 - stencilShadow;\r
+ break;\r
+ case M_OFFSET_SHADOW:\r
+ offsetShadow = 1 - offsetShadow;\r
+ break;\r
+ case M_POSITIONAL:\r
+ directionalLight = 0;\r
+ break;\r
+ case M_DIRECTIONAL:\r
+ directionalLight = 1;\r
+ break;\r
+ case M_PERFORMANCE:\r
+ reportSpeed = 1 - reportSpeed;\r
+ break;\r
+ }\r
+ glutPostRedisplay();\r
+}\r
+\r
+/* When not visible, stop animating. Restart when visible again. */\r
+static void\r
+visible(int vis)\r
+{\r
+ if (vis == GLUT_VISIBLE) {\r
+ if (animation)\r
+ glutIdleFunc(idle);\r
+ } else {\r
+ if (!animation)\r
+ glutIdleFunc(NULL);\r
+ }\r
+}\r
+\r
+/* Press any key to redraw; good when motion stopped and\r
+ performance reporting on. */\r
+/* ARGSUSED */\r
+static void\r
+key(unsigned char c, int x, int y)\r
+{\r
+ if (c == 27) {\r
+ exit(0); /* IRIS GLism, Escape quits. */\r
+ }\r
+ glutPostRedisplay();\r
+}\r
+\r
+/* Press any key to redraw; good when motion stopped and\r
+ performance reporting on. */\r
+/* ARGSUSED */\r
+static void\r
+special(int k, int x, int y)\r
+{\r
+ glutPostRedisplay();\r
+}\r
+\r
+static int\r
+supportsOneDotOne(void)\r
+{\r
+ const char *version;\r
+ int major, minor;\r
+\r
+ version = (char *) glGetString(GL_VERSION);\r
+ if (sscanf(version, "%d.%d", &major, &minor) == 2)\r
+ return major >= 1 && minor >= 1;\r
+ return 0; /* OpenGL version string malformed! */\r
+}\r
+\r
+int\r
+main(int argc, char **argv)\r
+{\r
+ int i;\r
+\r
+ glutInit(&argc, argv);\r
+\r
+ for (i=1; i<argc; i++) {\r
+ if (!strcmp("-linear", argv[i])) {\r
+ linearFiltering = 1;\r
+ } else if (!strcmp("-mipmap", argv[i])) {\r
+ useMipmaps = 1;\r
+ } else if (!strcmp("-ext", argv[i])) {\r
+ forceExtension = 1;\r
+ }\r
+ }\r
+\r
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_STENCIL | GLUT_MULTISAMPLE);\r
+\r
+#if 1\r
+ /* In GLUT 4.0, you'll be able to do this an be sure to\r
+ get 2 bits of stencil if the machine has it for you. */\r
+ glutInitDisplayString("samples stencil>=2 rgb double depth");\r
+#endif\r
+\r
+ glutCreateWindow("Shadowy Leapin' Lizards");\r
+\r
+ if (glutGet(GLUT_WINDOW_STENCIL_SIZE) <= 1) {\r
+ printf("dinoshade: Sorry, I need at least 2 bits of stencil.\n");\r
+ exit(1);\r
+ }\r
+\r
+ /* Register GLUT callbacks. */\r
+ glutDisplayFunc(redraw);\r
+ glutMouseFunc(mouse);\r
+ glutMotionFunc(motion);\r
+ glutVisibilityFunc(visible);\r
+ glutKeyboardFunc(key);\r
+ glutSpecialFunc(special);\r
+\r
+ glutCreateMenu(controlLights);\r
+\r
+ glutAddMenuEntry("Toggle motion", M_MOTION);\r
+ glutAddMenuEntry("-----------------------", M_NONE);\r
+ glutAddMenuEntry("Toggle light", M_LIGHT);\r
+ glutAddMenuEntry("Toggle texture", M_TEXTURE);\r
+ glutAddMenuEntry("Toggle shadows", M_SHADOWS);\r
+ glutAddMenuEntry("Toggle reflection", M_REFLECTION);\r
+ glutAddMenuEntry("Toggle dinosaur", M_DINOSAUR);\r
+ glutAddMenuEntry("-----------------------", M_NONE);\r
+ glutAddMenuEntry("Toggle reflection stenciling", M_STENCIL_REFLECTION);\r
+ glutAddMenuEntry("Toggle shadow stenciling", M_STENCIL_SHADOW);\r
+ glutAddMenuEntry("Toggle shadow offset", M_OFFSET_SHADOW);\r
+ glutAddMenuEntry("----------------------", M_NONE);\r
+ glutAddMenuEntry("Positional light", M_POSITIONAL);\r
+ glutAddMenuEntry("Directional light", M_DIRECTIONAL);\r
+ glutAddMenuEntry("-----------------------", M_NONE);\r
+ glutAddMenuEntry("Toggle performance", M_PERFORMANCE);\r
+ glutAttachMenu(GLUT_RIGHT_BUTTON);\r
+ makeDinosaur();\r
+\r
+#ifdef GL_VERSION_1_1\r
+ if (supportsOneDotOne() && !forceExtension) {\r
+ polygonOffsetVersion = ONE_DOT_ONE;\r
+ glPolygonOffset(-2.0, -1.0);\r
+ } else\r
+#endif\r
+ {\r
+#ifdef GL_EXT_polygon_offset\r
+ /* check for the polygon offset extension */\r
+ if (glutExtensionSupported("GL_EXT_polygon_offset")) {\r
+ polygonOffsetVersion = EXTENSION;\r
+ glPolygonOffsetEXT(-0.1, -0.002);\r
+ } else\r
+#endif\r
+ {\r
+ polygonOffsetVersion = MISSING;\r
+ printf("\ndinoshine: Missing polygon offset.\n");\r
+ printf(" Expect shadow depth aliasing artifacts.\n\n");\r
+ }\r
+ }\r
+\r