/* Opdracht 1 Door Bernard van Gastel, 0121363, Speciale functies: - geanimeerd in en uitzoemen, en transleren - met de muis slepen van de grafiek - double buffering */ #ifdef DARWIN #include #else #include #endif #include #include #include // grootte en titel van scherm int width=640, height=480; char* title = "ICG opdracht 1; Bernard van Gastel (0121363)"; // de 'resolutie' van de grafiek, geeft de intervallen aan, om welke deze meetpunten verricht GLdouble res; // de hoeken van het tekenscherm GLdouble xmin, ymin, xmax, ymax; // tijdens de animatie de doelhoeken van het scherm GLdouble txmin, tymin, txmax, tymax; // tijdens de animatie de bronhoeken van het scherm GLdouble sxmin, symin, sxmax, symax; int anim; // animation boolean GLdouble speed; // snelheid van de animatie // laatste tijd, belangrijk voor het berekenen van de animaties, om de verlopentijd te berekenen (en dus de snelheid) int scenetime = 0; // de laatste coordinaten van de muis, belangrijk voor het slepen van de grafiek met de muis int mousex, mousey; // zet tekst op het scherm void drawText(GLdouble x, GLdouble y, char s[]) { int i, length; char c; /* Ga naar gewenste beginpositie. */ glRasterPos2d (x, y); length = strlen (s); for (i=0; i 0.0) { xaxisy = ymin; } else if (ymax < size) { xaxisy = ymax - size; } else xaxisy = 0.0; // reken uit hoe ver van de as de tekst moet staan (7 pixels) start = (ymax - ymin)*7 / height; // laat de teksten zien for (i = xmin; i < xmax; i += (xmax - xmin) / 10.0) { sprintf(text, "%.3f", i); // zorg ervoor dat de tekst gecentreerd is, op de assen, dit heeft direct met de lengte van de tekst te maken, dus dit moet voor elk getal apart uitgerekent worden size = (GLdouble)((strlen(text)-1) * 13 * (xmax - xmin)/width); drawText(i-(size/2.0), start + xaxisy, text); } // y-as // reken uit hoe ver de tekst van de assen af moet staan (7 pixels) start = (xmax - xmin)*7 / width; // reken het middelpunt uit van de tekst (zodat deze gecentreerd op de assen komt te staan, deze is voor alle y-assen gelijk, aangezien de tekst altijd even hoog is size = (GLdouble)(8 * (ymax - ymin)/height); // laat de teksten zien for (i = ymin; i < ymax; i += (ymax - ymin) / 10.0) { GLdouble sizew; sprintf(text, "%.3f", i); // kijk waar de tekst op het scherm gezet moet worden, de tekst moet wel zichbaar zijn sizew = (GLdouble)((strlen(text)-1) * 13 * (xmax - xmin)/width); if (xmin > 0.0) { yaxisx = xmin; } else if (xmax < sizew) { yaxisx = xmax - sizew; } else yaxisx = 0.0; drawText(start + yaxisx, i - (size/2.0), text); } // teken de assen // kleur is wit glColor3f(1.0, 1.0, 1.0); // de lijnen zijn stippellijnen glEnable (GL_LINE_STIPPLE); glLineStipple (1, (GLushort) 0x0F0F); // teken de lijnen over het hele scherm heen glBegin(GL_LINES); // de assen komen over het hele venster glVertex2d(xmin, 0.0); glVertex2d(xmax, 0.0); glVertex2d(0.0, ymin); glVertex2d(0.0, ymax); glEnd(); glDisable(GL_LINE_STIPPLE); // wis de geheugenlocatie voor de standaard tekst free(text); } // a 'random' math function GLdouble mathFunc(GLdouble x) { return 2*sin(x/2)*cos(x); //(log(x)/log(3.0))/(24.0*cos(x)); //2*sin(x/2)*cos(x); } // teken op het scherm void draw(void) { // stel het window in setWindow(); // maak, als er gescrolt wordt, de lijnen dikker zodat ze ook tijden de animatie goed te zien zijn //glLineWidth(1.0 + anim); // teken de assen drawAxis(); // teken verschillende functies op het scherm, met bepaalde kleuren glColor3f(1.0, .0, .0); drawFunction(sin, 0.0); glColor3f(.0, .0, 1.0); drawFunction(cos, 0.0); glColor3f(.0, 1.0, .0); //drawFunction(mathFunc, 0.0); //glColor3f(1.0, 1.0, .0); glTranslatef(.0, 1.0, .0); drawFunction(mathFunc, 2.0); } // rekent de volgende waarde van een bepaald doel uit, als de snelheid en de bron en de huidige is meegeven. nodig voor het geanimeerd scrollen van de grafiek GLdouble calculateNext(GLdouble current, GLdouble target, GLdouble source, GLdouble speed, int time) { GLdouble tmp = current + (target - source) * speed * time / 1000; if ( (current > target && tmp < target) || (current < target && tmp > target)) return target; return tmp; } // reken de nieuwe grote van de schermcoordinaten void animScene(int time) { // als de doel ongelijk is een de bron, dan reken een extra waarde uit if (xmin != txmin) xmin = calculateNext(xmin, txmin, sxmin, speed, time); if (xmax != txmax) xmax = calculateNext(xmax, txmax, sxmax, speed, time); if (ymin != tymin) ymin = calculateNext(ymin, tymin, symin, speed, time); if (ymax != tymax) ymax = calculateNext(ymax, tymax, symax, speed, time); // als de doelwaardes bereikt zijn, hoefd er niet meer geanimeerd te worden if (xmin == txmin && xmax == txmax && ymin == tymin && ymax == tymax) anim = 0; } // initalisatie void init(void) { xmin = -6.0; ymin = -1.0; xmax = 6.0; ymax = 1.0; anim = 0; speed = 0.25; printf("%s%s%s%s%s%s%s%s%s", "Toetsenverklaring:\n", "\ta,z + s,x + d,c\t zoom respectievelijk de (x+y), x, y as(sen) respectivelijk in of uit (met een factor 2)\n", "\tq of ESC\tStoppen\n", "\tr\treset naar de beginwaardes\n", "\ti en k\ttransleer de grafiek 1/4 scherm omhoog (i) of omlaag (k)\n", "\tj en l\ttransleer de grafiek 1/4 scherm naar links (j) of naar rechts (l)\n", "\t+ en -\tverander de snelheid van de animatie\n", "\tspatie\tzet de animatie stil, en blijf op deze waarde\n", "\tmuis\tversleep de grafiek\n" ); } void display(void) { // bereken de verlopen tijd van de animatie in miliseconden, en animeer alles int oldscene = scenetime; scenetime = glutGet(GLUT_ELAPSED_TIME); if (anim) animScene(scenetime-oldscene); // leeg de buffer glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* echte tekenen */ draw(); // flush en swap buffers, komt nu echt op het scherm te staan, tegen flikkeren glFlush(); glutSwapBuffers(); } void startAnimate(void); // transleer de grafiek met een bepaalde waarde, en geef aan of deze geanimeerd moet worden of niet void translateGraph(GLdouble x, GLdouble y, int animate) { sxmin = xmin; txmin = xmin + x; sxmax = xmax; txmax = xmax + x; symin = ymin; tymin = ymin + y; symax = ymax; tymax = ymax + y; if (animate) startAnimate(); else { // als er niet geanimeerd moet worden, dan zijn de doelcoordinaten meteen de huidige coordinaten xmin = txmin; xmax = txmax; ymin = tymin; ymax = tymax; glutPostRedisplay(); } } // verklein/vergroot de grafiek void scaleGraph(GLdouble xfactor, GLdouble yfactor, int animate) { GLdouble centerx = (xmax - xmin)/2.0 + xmin; GLdouble centery = (ymax - ymin)/2.0 + ymin; // de oorsponkelijke coordinaten zijn de huidige sxmin = xmin; sxmax = xmax; symin = ymin; symax = ymax; // bereken de nieuwe doel coordinaten txmin = centerx - (centerx - xmin) * xfactor; txmax = txmin + (xmax - xmin) * xfactor; tymin = centery - (centery - ymin) * yfactor; tymax = tymin + (ymax - ymin) * yfactor; // kijk of de animatie aanstaat if (animate) startAnimate(); else { // als er niet geanimeerd moet worden, dan zijn de doelcoordinaten meteen de huidige coordinaten xmin = txmin; xmax = txmax; ymin = tymin; ymax = tymax; // en laat het zien glutPostRedisplay(); } } void key(unsigned char key, int x, int y) { void animate(void); switch (key) { // ga uit het programma case 27: case 'q': exit(0); break; // reset de grafiek case 'r': init(); break; // zoom de grafiek uit case 'a': scaleGraph(2.0, 2.0, 1); break; // zoom de grafiek in case 'z': scaleGraph(0.5, 0.5, 1); break; // zoom de x-as uit case 's': scaleGraph(2.0, 1.0, 1); break; // zoom de x-as in case 'x': scaleGraph(0.5, 1.0, 1); break; // zoom de y-as uit case 'd': scaleGraph(1.0, 2.0, 1); break; // zoom de y-as in case 'c': scaleGraph(1.0, 0.5, 1); break; // voor de snelheid van het in en uitzoomen op, of verlaag het case '-': speed *= 0.8; break; case '+': case '=': speed *= 1.25; break; // de 'pijltjes' toetsen, verplaatst de grafiek case 'k': translateGraph(.0, -(ymax - ymin) / 4.0, 1); break; case 'i': translateGraph(.0, (ymax - ymin) / 4.0, 1); break; case 'j': translateGraph(-(xmax - xmin) / 4.0, .0, 1); break; case 'l': translateGraph((xmax - xmin) / 4.0, .0, 1); break; // stop de huidige animatie en blijf zo staan case ' ': anim = 0; break; default: break; } glutPostRedisplay(); } // onthoud de waarde waar je hebt geklikt aangezien de mouse motion handler zelf de translatie van de x en y as moet berekenen (en anders krijg je in 1x een super grote translatie die niet klopt) void mouse (int but, int state, int mx, int my ) { if (but == GLUT_LEFT_BUTTON) { mousex = mx; mousey = my; } } // transleer de grafiek met de resolutie van de x-as en de y-as void motion(int mx, int my) { GLdouble x = (xmax - xmin) / width; GLdouble y = (ymax - ymin) / height; // aantal relatief verplaatste pixels uitrekenen int dx = mousex - mx; int dy = mousey - my; // nodig voor de volgende keer het aantal relatief verplaatste pixels uitrekenen mousex = mx; mousey = my; // transleer ook echt, zonder animatie // de min voor de y-as is nodig om het gevoel aan de gebruik te geven dat hij de grafiek ook echt sleept translateGraph(dx*(x*1.0), -dy*(y*1.0), 0); } void reshape(int w, int h) { // maak de viewpoort naar het hele venster glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); // onthoud dit, belangrijk voor interactie van mouse, etc width = w; height = h; // zorg dat de veranderingen doorkomen glFlush(); } // de idle functie, die zorgt dat als er toch niks anders te doen is, alles opnieuw getekent wordt void animate(void) { if (anim) { /* tgwidth != gwidth || tgheight != gheight) { */ glutPostRedisplay(); } else glutIdleFunc(NULL); } // start een animatie void startAnimate(void) { anim = 1; glutIdleFunc(animate); scenetime = glutGet(GLUT_ELAPSED_TIME); } int main(int argc, char** argv) { // init glut glutInit(&argc, argv); // init wat modes met double buffering glutInitDisplayMode(GLUT_SINGLE| GLUT_RGBA | GLUT_DOUBLE); // init positsie glutInitWindowPosition(50,50); // init grootte glutInitWindowSize(width,height); // maak een window glutCreateWindow(title); // registreer de callback functies glutDisplayFunc(display); glutKeyboardFunc(key); glutReshapeFunc(reshape); glutIdleFunc(animate); glutMouseFunc(mouse); glutMotionFunc(motion); /* init */ init(); // wissel de buffers uit glutSwapBuffers(); // ga naar de hoofdloop glutMainLoop(); return 0; }