#include #include #include #include #include "Go.h" #include "GoGlutInterface.h" #include "GoText.h" #include "GoTorus.h" #define PI 3.14159265358979324 class GoClockDemo : public GoGlutInterface { public: enum { ROTATE_TYPE_X_Y, ROTATE_TYPE_Z, }; // clock numbers GoText *number[12]; // clock hands GoLines *hourHand; double hourHandLength; GoLines *minuteHand; double minuteHandLength; GoLines *secondHand; double secondHandLength; // clock body GoTorus *body; // clock orientation GoMatrix modelview; GoMatrix currentModelview; int xStart; int yStart; double angleStart; double rX, rY, rZ; int rotateType; // center point of clock double centerX, centerY, centerZ; // pergull boolean doingMousePressed; GoClockDemo() { // // Initialize clock numbers. // double angle = 2 * PI / 12; for(int i = 0; i < 12; i++) { char str[3]; sprintf(str, "%d", i + 1); double r = 0.8; double x = r * sin(angle); double y = r * cos(angle); number[i] = new GoText(x, y, 0.0, // position 1.0, 0.0, 0.0, // path 0.0, 1.0, 0.0, // up 0.2, 0.2, // scale GoText::CENTER_CENTER, // alignment new GoHershey("hersheyFonts/futura.l"), // font str); // text angle += 2 * PI / 12; } // // Initialize clock hands. // hourHandLength = 0.40; hourHand = new GoLines(2); hourHand->xyz(0, 0, 0, 0); minuteHandLength = 0.55; minuteHand = new GoLines(2); minuteHand->xyz(0, 0, 0, 0); secondHandLength = 0.65; secondHand = new GoLines(2); secondHand->xyz(0, 0, 0, 0); // // Initialize clock body. // body = new GoTorus(1.05, 12, 0.1, 12); // // Set center coordinate of clock. // centerX = centerY = centerZ = 0; // // Turn on LIGHT_0 // go->light(Go::LIGHT_0, true); go->light(Go::LIGHT_0, Go::DIRECTIONAL, 1.0, 1.0, 1.0); // // Clock background color. // go->background(0.2, 0.2, 0.2); // pergull doingMousePressed = false; } void render(void) { // // Clear. // go->clear(Go::IMAGE); // // Setup clock hands. // setHourHand(); setMinuteHand(); setSecondHand(); // // Draw clock. // // clock numbers go->color(1, 1, 0); // yellow for(int i = 0; i < 12; i++) { number[i]->render(go); } // clock hands go->color(1, 1, 1); // white go->render(hourHand); go->render(minuteHand); go->render(secondHand); // clock body go->color(0, 0, 1); // blue body->renderSolid(go); go->color(1.0, 0.5, 0.1); // salmon body->renderWireSlices(go); // // Display. // swap(); // // Post render event to update clock time. // // pergull //if(!doingMousePressed) // sleep(1); rerender(); } void mousePressed(int x, int y) { // pergull doingMousePressed = true; int width = go->width(); int height = go->height(); // // Rotate about X-Y axiz or Z axis? // int zRotSensitivity = 10; // NOTE: A smaller number makes the z-axis // rotation more sensitive. I.e. you // can be more sloppy to make it rotate // about the z-axis with a smaller number. rotateType = x > width / zRotSensitivity && x < width * (zRotSensitivity - 1) / zRotSensitivity && y > height / zRotSensitivity && y < height * (zRotSensitivity - 1) / zRotSensitivity ? ROTATE_TYPE_X_Y : ROTATE_TYPE_Z; switch(rotateType) { case ROTATE_TYPE_X_Y: { // // Init mouse info. // xStart = x; yStart = y; go->getModelview(¤tModelview); } break; case ROTATE_TYPE_Z: { // // Init mouse info. // xStart = x; yStart = y; angleStart = atan2(height / 2.0 - yStart, xStart - width / 2.0); // // Save the current modelview matrix so that // it can be restored as the mouse is moved. // go->getModelview(¤tModelview); // // Calc the rotation vector // double x0 = 0.0; double y0 = 0.0; double z0 = 0.0; double x1; double y1; double z1; x1 = 0.0; y1 = 0.0; z1 = 1.0; go->push(Go::MODELVIEW); go->inverse(); go->getModelview(&modelview); go->pop(Go::MODELVIEW); double *m = modelview.m; double w = m[3] * x0 + m[7] * y0 + m[11] * z0 + m[15]; double x0N = (m[0] * x0 + m[4] * y0 + m[8] * z0 + m[12]) / w; double y0N = (m[1] * x0 + m[5] * y0 + m[9] * z0 + m[13]) / w; double z0N = (m[2] * x0 + m[6] * y0 + m[10] * z0 + m[14]) / w; w = m[3] * x1 + m[7] * y1 + m[11] * z1 + m[15]; double x1N = (m[0] * x1 + m[4] * y1 + m[8] * z1 + m[12]) / w; double y1N = (m[1] * x1 + m[5] * y1 + m[9] * z1 + m[13]) / w; double z1N = (m[2] * x1 + m[6] * y1 + m[10] * z1 + m[14]) / w; rX = x1N - x0N; rY = y1N - y0N; rZ = z1N - z0N; } break; } } void mouseDragged(int x, int y) { int xEnd = x; int yEnd = y; switch(rotateType) { case ROTATE_TYPE_X_Y: { go->identity(); double xTheta = (yEnd - yStart) / 2; double yTheta = (xEnd - xStart) / 2; go->rotate(xTheta, 1, 0, 0); go->rotate(yTheta, 0, 1, 0); go->multiply(¤tModelview); } break; case ROTATE_TYPE_Z: { int width = go->width(); int height = go->height(); go->load(¤tModelview); double angleEnd = atan2(height / 2.0 - yEnd, xEnd - width / 2.0); double delta = (angleEnd - angleStart) * 180.0 / PI; go->translate(centerX, centerY, centerZ); go->rotate(delta, rX, rY, rZ); go->translate(-centerX, -centerY, -centerZ); } break; } } void mouseReleased(int x, int y) { // pergull doingMousePressed = false; } void resized(int width, int height) { // // Setup projection matrix. // go->push(Go::MATRIX_MODE); go->matrixMode(Go::PROJECTION); go->identity(); if(width > height) { go->ortho(-1.2 * width / height, 1.2 * width / height, -1.2, 1.2, -1.2, 1.2); } else { go->ortho(-1.2, 1.2, -1.2 * height / width, 1.2 * height / width, -1.2, 1.2); } go->pop(Go::MATRIX_MODE); } // // Returns the current hour. // int hour() { char s[100]; time_t t; time(&t); strftime(s, 100, "%I", localtime((const time_t *)&t)); return atoi(s); } // // Returns the current minute. // int minute() { char s[100]; time_t t; time(&t); strftime(s, 100, "%M", localtime((const time_t *)&t)); return atoi(s); } // // Returns the current second. // int second() { char s[100]; time_t t; time(&t); strftime(s, 100, "%S", localtime((const time_t *)&t)); return atoi(s); } // // Setup the clock's hour hand. // void setHourHand() { int hoursPassed = hour(); int minutesPassed = minute(); double angle = 2 * PI / 12 * hoursPassed + 2 * PI / 12 / 60 * minutesPassed; double x = hourHandLength * sin(angle); double y = hourHandLength * cos(angle); hourHand->xyz(1, x, y, 0); } // // Setup the clock's minute hand. // void setMinuteHand() { int minutesPassed = minute(); double angle = 2 * PI / 60 * minutesPassed; double x = minuteHandLength * sin(angle); double y = minuteHandLength * cos(angle); minuteHand->xyz(1, x, y, 0); } // // Setup the clock's second hand. // void setSecondHand() { int secondsPassed = second(); double angle = 2 * PI / 60 * secondsPassed; double x = secondHandLength * sin(angle); double y = secondHandLength * cos(angle); secondHand->xyz(1, x, y, 0); } }; int main(int argc, char *argv[]) { GoGlutInterface::init(&argc, argv); new GoClockDemo(); GoGlutInterface::mainLoop(); return(0); }