/* Tutor on NURB curves (1-dimension) Written by Caroline Geiersbach and Scott D. Anderson scott.anderson@acm.org Summer 2003 */ #include #include #include #include #include "tw.h" //window stuff GLuint window, adjustable, world, command; #define GAP 25 //gap between subwindows int cWinWidth = 450; //command window width int cWinHeight = 450; //command window height int wWinWidth = 450; //world window width int wWinHeight = 550; //world window height int mWinWidth = 900+GAP*3; //main window width int mWinHeight = 600; //main window height //for picking int count; int p=15; //unselected point int k=31; //unselected knot //global parameters for the knots GLfloat uKnot[30]; GLfloat knotXVal[30]; //position of knots on screen static int numPoints; static int uOrder; static int numKnots; GLUnurbsObj *myNurb; void redisplayAll(); //specify all control points here GLfloat points[15][4] = { {-7,-3,1,1}, {-6,-3,1,1}, {-5,0,1,1}, {-4,-5,1,1}, {-3,5,1,1}, {-2,-3,1,1}, {-1,3,1,1}, {0,-16,1,1}, {1,0,1,1}, {2,-3,1,1}, {3,-10,1,1}, {4,13,1,1}, {5,-10,1,1}, {6,-3,1,1},{7,-4,1,1}, }; GLfloat originalPoints[15][4] = { {-7,-3,1,1}, {-6,-3,1,1}, {-5,0,1,1}, {-4,-5,1,1}, {-3,5,1,1}, {-2,-3,1,1}, {-1,3,1,1}, {0,-16,1,1}, {1,0,1,1}, {2,-3,1,1}, {3,-10,1,1}, {4,13,1,1}, {5,-10,1,1}, {6,-3,1,1},{7,-4,1,1}, }; //cells are used in the command window; each cell has an id; a //raster location at x,y; min and max values; a current value; the //step for adjusting values; info on what the cell specifies; and //finally the format of the printed values. typedef struct _cell { int id; int x, y; GLfloat min, max; GLfloat value; GLfloat step; char* info; char* format; } cell; cell pickedPoint[4] = { { 1, 180, 260, -24.0, 24.0, 0.0, 0.05, "Specifies X coordinate of point that was last clicked.", "%.2f" }, { 2, 240, 260, -24.0, 24.0, 0.0, 0.05, "Specifies Y coordinate of point that was last clicked.", "%.2f" }, { 3, 300, 260, -24.0, 24.0, 0.0, 0.0, //z coord non-adjustable "Specifies Z coordinate of point that was last clicked.", "%.2f" }, { 4, 360, 260, 0, 50.0, 1.0, 0.5, "Specifies weight of the point that was last clicked.", "%.2f" }, }; cell curveParams[2] = { {5, 225, 100, 0, 15, 15, 1, "Specifies the number of control points for the curve.", "%.1f"}, {6, 150, 180, 0, 15, 3, 1, "Specifies the order of the curve.", "%.1f"}, }; GLint selection = 0; int old_y; //for command mouse //moves information from command window to corresponding global variables void setVals () { numPoints = (int)curveParams[0].value; uOrder = (int)curveParams[1].value; numKnots = numPoints + uOrder; } /* void setWeights() { int i, j; for (i = 0; i < numPoints; i++) { pt[i][3] = points[i][3]; for(j = 0; j<3; j++) { pt[i][j] = points[i][3]*pt[i][3]; } } printf("curve with weights:\n"); for(i=0;i=uOrder) { for(i=0; i screen[0]-4 && yscreen[1]-4) { return i; } } return 15; } void adjust(int x, int y, int element) { if(p<15) { twTriple world; //new coords for element twTriple A,B,V; twTriple winA = {x,y,0}; twTriple winB = {x,y,1}; twUnProject(A,winA); twUnProject(B,winB); twVector(V,B,A); twPointOnLine(points[element],A,V,0.5); //setWeights(); } } static int mouse_x, mouse_y; void worldMouse(int button, int state, int x, int y) { y=wWinHeight-y; if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN){ mouse_x=x; mouse_y=y; p = pick(x,y); } redisplayAll(); } void worldMotion(int x, int y) { y=wWinHeight-y; adjust(x,y,p); redisplayAll(); } void worldInit() { int i,k, j; glutMouseFunc(worldMouse); glutMotionFunc(worldMotion); myNurb=gluNewNurbsRenderer(); gluNurbsProperty(myNurb,GLU_DISPLAY_MODE,GLU_FILL); glEnable(GL_MAP1_VERTEX_3); // glEnable(GL_MAP1_VERTEX_4); setVals(); makeKnots(uOrder,numPoints,uKnot); setKnotXVal(); /* for (i = 0; i < numPoints; i++) { pt[i][3] = points[i][3]; for(j = 0; j<3; j++) { pt[i][j] = points[i][j]*pt[i][3];//points1[i][j]*points[i][3]; } }*/ /*setWeights(); printf("curve with weights:\n"); for(k=0;kid) { twColorName(TW_CYAN); //color of info text twDrawString(10, 20, cell->info); } twDrawString(cell->x, cell->y, cell->format, cell->value); } //returns cell id if cell has been clicked on; 0 otherwise int cellHit(cell* cell, int x, int y) { if (x > cell->x && x < cell->x+55 && y > cell->y-15 && y < cell->y+15){ return cell->id; } return 0; } //updates the cell's value void cellUpdate(cell* cell, int update) { if (selection != cell->id) return; cell->value += update * cell->step; //tests for min and max values of the points if (cell->value < cell->min) cell->value = cell->min; else if (cell->value > cell->max) cell->value = cell->max; setVals(); if(cell->id ==5 || cell->id==6) {//curve params change; redo knots printf("uOrder = %i, numPoints = %i\n", uOrder, numPoints); makeKnots(uOrder,numPoints,uKnot); setKnotXVal(); } } //display on right side; where user can adjust values void commandDisplay() { //set up camera glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, cWinWidth, cWinHeight, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(0.0, 0.0, 0.0, 1.0); //clear to black glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); twSetFont("helvetica", 18); twDrawString(10, curveParams[0].y, "number of control points:"); twDrawString(10, curveParams[1].y, "order of curve:"); cellDraw(&curveParams[0]); cellDraw(&curveParams[1]); if(p<15) { //point has been selected pickedPoint[0].value = points[p][0]; pickedPoint[1].value = points[p][1]; pickedPoint[2].value = points[p][2]; pickedPoint[3].value = points[p][3]; twDrawString(10, pickedPoint[0].y, "point coordinates = ("); twDrawString(pickedPoint[0].x+55, pickedPoint[0].y, ","); twDrawString(pickedPoint[1].x+55, pickedPoint[1].y, ","); twDrawString(pickedPoint[2].x+55, pickedPoint[2].y, ","); twDrawString(pickedPoint[3].x+55, pickedPoint[3].y, ");"); cellDraw(&pickedPoint[0]); cellDraw(&pickedPoint[1]); cellDraw(&pickedPoint[2]); cellDraw(&pickedPoint[3]); } else { twColorName(TW_ORANGE); twDrawString(10, pickedPoint[0].y, "click on point to view its coords."); } twColorName(TW_RED); if(k<31) { //knot has been selected twDrawString(10, 340, "knot index: %i", k); twDrawString(10, 380, "knot value: %.2f", uKnot[k]); } else { twDrawString(10,340, "no knot selected"); } if (!selection) { twColorName(TW_CYAN); twDrawString(10, 20, "Click on args and move mouse to modify values."); } //directions at bottom of command window twColorName(TW_CYAN); twDrawString(10,425, "Hit

to print point and knot values."); twColorName(TW_WHITE); glutSwapBuffers(); } void commandMouse(int button, int state, int x, int y) { selection = 0; if(state == GLUT_DOWN) { /* mouse should only hit _one_ of the cells, so adding up all the hits just propagates a single hit. */ selection += cellHit(&curveParams[0], x, y); selection += cellHit(&curveParams[1], x, y); selection += cellHit(&pickedPoint[0], x, y); selection += cellHit(&pickedPoint[1], x, y); selection += cellHit(&pickedPoint[2], x, y); selection += cellHit(&pickedPoint[3], x, y); } old_y = y; redisplayAll(); } //sets values of pickedPoint to the correct point in the points array void setPoint() { points[p][0] = pickedPoint[0].value; points[p][1] = pickedPoint[1].value; points[p][2] = pickedPoint[2].value; points[p][3] = pickedPoint[3].value; // setWeights(); } /*void setNewWeights() { int i, j; for (i = 0; i < numPoints; i++) { points[i][3] = points1[i][3]; for(j = 0; j<3; j++) { points[i][j] = points1[i][j]*points[i][3]; } } } */ //allows for click and drag void commandMotion(int x, int y) { cellUpdate(&curveParams[0], old_y-y); cellUpdate(&curveParams[1], old_y-y); cellUpdate(&pickedPoint[0], old_y-y); cellUpdate(&pickedPoint[1], old_y-y); cellUpdate(&pickedPoint[2], old_y-y); cellUpdate(&pickedPoint[3], old_y-y); setPoint(); old_y = y; redisplayAll(); } /* ADJUSTABLE */ void adjustableDisplay() { int i; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0, cWinWidth, 75, 0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClearColor(0.0, 0.0, 0.0, 1.0); //clear to black glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //horizontal line twColorName(TW_RED); glLineWidth(3); glBegin(GL_LINES); glVertex2f(0,40); glVertex2f(cWinWidth, 40); glEnd(); //vertical lines twColorName(TW_WHITE); glPushMatrix(); glLineWidth(2); for(i=0; i0 && knotXVal[i]knotXVal[i]-5 && y<45 && y>35) { //printf("selected knot: %i\n",i); return i; } } return 31; //did not click on a knot } //changes knotXVal[element] to x, finds the new knot value void knotAdjust(int x, int y, int element) { if(k<31) { knotXVal[element]=x; uKnot[element]= (float)x*(numPoints-uOrder+1)/(cWinWidth); } } int aMouse_x, aMouse_y; void adjustableMouse(int button, int state, int x, int y) { if(button==GLUT_LEFT_BUTTON && state==GLUT_DOWN){ aMouse_x=x; aMouse_y=y; k = knotPick(x,y); } redisplayAll(); } void adjustableMotion(int x, int y) { knotAdjust(x,y,k); redisplayAll(); } void printVals(unsigned char key, int x, int y) { int i; int numPoints = (int)curveParams[0].value; int order = (int)curveParams[1].value; printf("numPoints = %i, order = %i\n", numPoints, order); printf("Your current control points are: \n"); for(i=0; i