/*===========================================================================* * * YACME * Yet Another ColorMap Editor * * Patrick BOUCHAUD - 1993 * SGI Switzerland * * Converted to OpenGL using GLUT * *===========================================================================*/ #include #include #include #include #include #include "mallocbis.h" /* For portability... */ #undef fsqrt #define fsqrt(_a) sqrt(_a) #define SUP(a,b) ( ((a)>(b)) ? (a) : (b) ) #define INF(a,b) ( ((a)<(b)) ? (a) : (b) ) #define ABS(a) ( ((a)<0) ? -(a) : (a) ) #define POINT 1 #define CURVE 2 #define LEFT_TAN 3 #define RIGHT_TAN 4 #define MANUAL 1 #define CONTINUOUS 2 #define CONSTANT 1 #define LINEAR 2 #define POLYNOMIAL 3 #define TabCmpnt(c,n) TabCmpnt[(n)*4+(c)] #define MAXNDX (dimlut-1) #define WINHEIGHT 381 #define WINWIDTH 318 #define LUTRATIO ((float)MAXNDX/255.) #define LEFT LUTRATIO*(-5.) #define RIGHT LUTRATIO*(260.) #define BOTTOM LUTRATIO*(-5.) #define TOP LUTRATIO*(315.) #define TANLEN LUTRATIO*(25.) typedef float Matrix[4][4]; typedef struct { float x0, y0, x1, y1; } Tangente; typedef struct UserPointStruct { float x, y; Tangente tg; int mode; float polynome[4]; struct UserPointStruct *next, *last; } UserPoint; void ResetCMap(void); void ApplyCMap(void); void YACME_makeMenu(void); extern void invertmat(float from[4][4], float to[4][4]); static UserPoint *FreePointList = NULL; #define newPoint( point ) newItem( point, FreePointList, UserPoint ) #define freePoint( point ) freeItem( point, FreePointList ) typedef struct { int type, cmpnt, ndx; UserPoint *upoint; } PickObject; struct { int leftdown, middledown, rightdown; } mouse; void YACME_pick( int mx, int my, PickObject *obj ); void YACME_update( int cmpnt, UserPoint *upoint ); int YACME_get( unsigned long *table ); void DeletePoint( int cmpnt, UserPoint *upoint ); int MovePoint( int, int ); int MoveTangente( int, int, int ); int InsertPoint( PickObject *obj ); void GetPolynome( int mode, float a0, float b0, float t0, float a1, float b1, float t1, float coeff[4] ); void OrthoTransform( int mx, int my, float *x, float *y ); float Polynome4( float x, float *polynome ); static int DrawCurve[4] = { 1, 1, 1, 1, }, modifiedCurve[4] = { 1, 1, 1, 1 }, YACME_refresh = MANUAL, curCmpnt = 0, curType = 0, Mousex, Mousey; static float *TabCmpnt; static int YACME_switch_menu = 0, YACME_mode_menu, YACME_edit_menu; static int YACME_win = 0, W, H , update = 0; static UserPoint *userPoint[4], *userPointSvg[4], *curPoint = NULL; static void Redraw( void ); static void Reshape( int, int ); static void Mouse( int, int, int, int ); static void Motion( int, int ); static void Key( unsigned char, int, int ); static void Special( int, int, int ); static void YACME_menuFunc( int ); typedef void (*CallBack)(void); static CallBack newmapCB, applyCB; static int dimlut; /*---------------------------------------------------------------------------* * YACME_init *---------------------------------------------------------------------------*/ void YACME_init( int x, int y, int w, int h, int dim, float **list, CallBack newmapFunc, CallBack applyFunc) { int i, j; UserPoint *userpoint; if (YACME_win) return; dimlut = dim; newmapCB = newmapFunc; applyCB = applyFunc; if (*list==NULL) { *list = TabCmpnt = (float *) malloc( 4*dimlut*sizeof(float) ); for (i=0; i<4; i++) { newPoint( userPoint[i] ); userpoint = userPoint[i]; userpoint->mode = POLYNOMIAL; userpoint->x = 0.; userpoint->y = 0.; userpoint->last = NULL; userpoint->tg.x0 = 0.; userpoint->tg.y0 = 0.; userpoint->tg.x1 = TANLEN; userpoint->tg.y1 = 0.; newPoint( userpoint->next ); userpoint = userpoint->next; userpoint->mode = POLYNOMIAL; userpoint->x = (float)MAXNDX; userpoint->y = (float)MAXNDX; userpoint->last = userPoint[i]; userpoint->next = NULL; userpoint->tg.x0 = (float)(MAXNDX-TANLEN); userpoint->tg.y0 = (float)MAXNDX; userpoint->tg.x1 = (float)MAXNDX; userpoint->tg.y1 = (float)MAXNDX; } } else { UserPoint *upoint[4], *lastupoint[4]={0,0,0,0}; TabCmpnt = *list; for (i=0; inext ); upoint[j] = upoint[j]->next; } upoint[j]->next = NULL; upoint[j]->last = lastupoint[j]; upoint[j]->mode = LINEAR; upoint[j]->x = (float)i; upoint[j]->y = (float)MAXNDX*TabCmpnt(j,i); if (i==0) { upoint[j]->tg.x0 = 0.; upoint[j]->tg.y0 = 0.; upoint[j]->tg.x1 = TANLEN; upoint[j]->tg.y1 = 0.; } else { float slope = upoint[j]->y - upoint[j]->last->y, dx = TANLEN/fsqrt(slope*slope + 1), dy = slope*dx; upoint[j]->tg.x0 = upoint[j]->x - dx; upoint[j]->tg.y0 = upoint[j]->y - dy; upoint[j]->tg.x1 = upoint[j]->x + dx; upoint[j]->tg.y1 = upoint[j]->y + dy; } lastupoint[j] = upoint[j]; } } } /* TabComponents update -------------------- */ for (i=0; i<4; i++) { for (userpoint=userPoint[i]; userpoint!=NULL; userpoint=userpoint->next) YACME_update( i, userpoint ); } ApplyCMap(); if (!YACME_win) { glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE ); glutInitWindowPosition( x, y ); glutInitWindowSize( w, h ); YACME_win = glutCreateWindow( "LUT editor" ); glutDisplayFunc( Redraw ); glutReshapeFunc( Reshape ); glutMouseFunc( Mouse ); glutMotionFunc( Motion ); glutPassiveMotionFunc( Motion ); glutSpecialFunc( Special ); glutKeyboardFunc( Key ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glOrtho( LEFT, RIGHT, BOTTOM, TOP, -1., 1. ); glClearColor( 0.66, 0.66, 0.66, 1. ); glClear( GL_COLOR_BUFFER_BIT ); glShadeModel( GL_FLAT ); glutSwapBuffers(); YACME_makeMenu(); } } /*---------------------------------------------------------------------------* * Key *---------------------------------------------------------------------------*/ /* ARGSUSED1 */ static void Key( unsigned char key, int x, int y ) { UserPoint *previousPoint; switch (key) { case 27: /* Escape */ exit(0); break; case 127: /* BackSpace */ case 8: /* Delete */ if (!curPoint) return; previousPoint = (curPoint->last ? curPoint->last : userPoint[curCmpnt]); DeletePoint( curCmpnt, curPoint ); modifiedCurve[curCmpnt] = 1; update = 1; curPoint = previousPoint; break; } glutPostRedisplay(); } /*---------------------------------------------------------------------------* * Special *---------------------------------------------------------------------------*/ /* ARGSUSED1 */ static void Special( int key, int xx, int yy ) { int x, y, minx, maxx; float dx, dy; if (curPoint == NULL ) return; if (curPoint->next == NULL) return; if (curPoint->last == NULL) return; x = (int)curPoint->x; y = (int)curPoint->y; minx = (int)curPoint->last->x; minx++; maxx = (int)curPoint->next->x; maxx--; switch (key) { case GLUT_KEY_LEFT: if (x > minx) x--; break; case GLUT_KEY_RIGHT: if (x < maxx) x++; break; case GLUT_KEY_UP: if (y < MAXNDX) y++; break; case GLUT_KEY_DOWN: if (y > 0) y--; break; } dx = (float)x - curPoint->x; curPoint->x += dx; curPoint->tg.x0 += dx; curPoint->tg.x1 += dx; dy = (float)y - curPoint->y; curPoint->y = y; curPoint->tg.y0 += dy; curPoint->tg.y1 += dy; update = 1; glutPostRedisplay(); } /*---------------------------------------------------------------------------* * Reshape *---------------------------------------------------------------------------*/ static void Reshape( int w, int h ) { glViewport( 0, 0, w, h ); W = w; H = h; glutPostRedisplay(); } /*---------------------------------------------------------------------------* * Mouse *---------------------------------------------------------------------------*/ static void Mouse( int button, int state, int x, int y ) { PickObject object; y = H-y; switch (button) { case GLUT_RIGHT_BUTTON: mouse.rightdown = (state==GLUT_DOWN); break; case GLUT_MIDDLE_BUTTON: mouse.middledown = (state==GLUT_DOWN); break; case GLUT_LEFT_BUTTON: mouse.leftdown = (state==GLUT_DOWN); if (mouse.leftdown) { YACME_pick( x, y, &object ); curType = object.type; switch ( object.type ) { case CURVE: if ((curType = InsertPoint( &object ) != 0)) { curPoint = object.upoint; curCmpnt = object.cmpnt; } else curPoint = NULL; break; case POINT: case LEFT_TAN: case RIGHT_TAN: curPoint = object.upoint; curCmpnt = object.cmpnt; break; default: curPoint = NULL; } break; } } glutPostRedisplay(); } /*---------------------------------------------------------------------------* * Motion *---------------------------------------------------------------------------*/ static void Motion( int x, int y ) { Mousex = x; Mousey = H-y; if (mouse.leftdown) { switch (curType) { case POINT: update = MovePoint( Mousex, Mousey ); break; case LEFT_TAN: update = MoveTangente( -1, Mousex, Mousey ); break; case RIGHT_TAN: update = MoveTangente( 1, Mousex, Mousey ); break; } } glutPostRedisplay(); } /*---------------------------------------------------------------------------* * YACME_makeMenu *---------------------------------------------------------------------------*/ #define CONTINUOUS_ITEM 5 #define MANUAL_ITEM 4 #define APPLY_ITEM 3 #define RESET_ITEM 2 #define CLOSE_ITEM 1 #define RED_ITEM 10 #define GREEN_ITEM 11 #define BLUE_ITEM 12 #define ALPHA_ITEM 13 #define CONSTANT_ITEM 22 #define LINEAR_ITEM 21 #define POLYNOM_ITEM 20 #define EDIT_RED_ITEM 30 #define EDIT_GREEN_ITEM 31 #define EDIT_BLUE_ITEM 32 #define EDIT_ALPHA_ITEM 33 void YACME_makeMenu(void) { YACME_edit_menu = glutCreateMenu( YACME_menuFunc ); glutAddMenuEntry( "red", EDIT_RED_ITEM ); glutAddMenuEntry( "green", EDIT_GREEN_ITEM ); glutAddMenuEntry( "blue", EDIT_BLUE_ITEM ); glutAddMenuEntry( "alpha", EDIT_ALPHA_ITEM ); YACME_mode_menu = glutCreateMenu( YACME_menuFunc ); glutAddMenuEntry( "Constant ", CONSTANT_ITEM ); glutAddMenuEntry( "Linear ", LINEAR_ITEM ); glutAddMenuEntry( "Polynomial", POLYNOM_ITEM ); YACME_switch_menu = glutCreateMenu( YACME_menuFunc ); glutAddMenuEntry( "Red on", RED_ITEM ); glutAddMenuEntry( "Green on", GREEN_ITEM ); glutAddMenuEntry( "Blue on", BLUE_ITEM ); glutAddMenuEntry( "Alpha on", ALPHA_ITEM ); glutCreateMenu( YACME_menuFunc ); glutAddMenuEntry( "Manual ", MANUAL_ITEM ); glutAddMenuEntry( "Apply", APPLY_ITEM ); glutAddMenuEntry( "Reset", RESET_ITEM ); glutAddMenuEntry( "Close", CLOSE_ITEM ); glutAddSubMenu( "Mode... ", YACME_mode_menu ); glutAddSubMenu( "Switch... ", YACME_switch_menu ); glutAddSubMenu( "Edit... ", YACME_edit_menu ); glutAttachMenu( GLUT_RIGHT_BUTTON ); } /*---------------------------------------------------------------------------* * YACME_menuFunc *---------------------------------------------------------------------------*/ static void YACME_menuFunc( int item ) { switch( item ) { case CLOSE_ITEM: break; case RESET_ITEM: if (applyCB) (*applyCB)(); else if (newmapCB) (*newmapCB)(); ResetCMap(); curPoint = NULL; break; case APPLY_ITEM: if (applyCB) (*applyCB)(); else if (newmapCB) (*newmapCB)(); ApplyCMap(); break; case MANUAL_ITEM: /* switch to continuous */ glutChangeToMenuEntry( 1, "Continuous", CONTINUOUS_ITEM ); YACME_refresh = CONTINUOUS; break; case CONTINUOUS_ITEM: /* switch to manual */ glutChangeToMenuEntry( 1, "Manual ", MANUAL_ITEM ); if (newmapCB) (*newmapCB)(); ApplyCMap(); YACME_refresh = MANUAL; break; case RED_ITEM: DrawCurve[0] = !DrawCurve[0]; if (DrawCurve[0]) glutChangeToMenuEntry( 1, "Red on", RED_ITEM ); else glutChangeToMenuEntry( 1, "Red off", RED_ITEM ); curPoint = NULL; break; case GREEN_ITEM: DrawCurve[1] = !DrawCurve[1]; if (DrawCurve[1]) glutChangeToMenuEntry( 2, "Green on", GREEN_ITEM ); else glutChangeToMenuEntry( 2, "Green off", GREEN_ITEM ); curPoint = NULL; break; case BLUE_ITEM: DrawCurve[2] = !DrawCurve[2]; if (DrawCurve[2]) glutChangeToMenuEntry( 3, "Blue on", BLUE_ITEM ); else glutChangeToMenuEntry( 3, "Blue off", BLUE_ITEM ); curPoint = NULL; break; case ALPHA_ITEM: DrawCurve[3] = !DrawCurve[3]; if (DrawCurve[3]) glutChangeToMenuEntry( 4, "Alpha on", ALPHA_ITEM ); else glutChangeToMenuEntry( 4, "Alpha off", ALPHA_ITEM ); curPoint = NULL; break; case CONSTANT_ITEM: if (curPoint != NULL) { update = 1; curPoint->mode = CONSTANT; } break; case LINEAR_ITEM: if (curPoint != NULL) { update = 1; curPoint->mode = LINEAR; } break; case POLYNOM_ITEM: if (curPoint != NULL) { update = 1; curPoint->mode = POLYNOMIAL; } break; case EDIT_RED_ITEM: case EDIT_GREEN_ITEM: case EDIT_BLUE_ITEM: case EDIT_ALPHA_ITEM: curCmpnt = item-30; curPoint = userPoint[curCmpnt]; break; } glutPostRedisplay(); } /*---------------------------------------------------------------------------* * output *---------------------------------------------------------------------------*/ static void output( float x, float y, char *string ) { int len, i; glRasterPos2f(x, y); len = (int) strlen(string); for (i = 0; i < len; i++) { glutBitmapCharacter(GLUT_BITMAP_8_BY_13, string[i]); } } /*---------------------------------------------------------------------------* * Redraw *---------------------------------------------------------------------------*/ static void Redraw( void ) { int i, j, ndx, cmpnt, priority[4]; Tangente *tg; UserPoint *upoint; char string[256]; if (update) { modifiedCurve[curCmpnt] = 1; YACME_update( curCmpnt, curPoint ); if ( newmapCB && (YACME_refresh == CONTINUOUS)) (*newmapCB)(); update = 0; } glClear( GL_COLOR_BUFFER_BIT ); /* Barettes representant la table des couleurs ------------------------------------------- */ glBegin( GL_TRIANGLE_STRIP ); glColor3f(TabCmpnt(0,0), TabCmpnt(1,0), TabCmpnt(2,0)); glVertex2f( 0., 270.*LUTRATIO ); glVertex2f( 0., 310.*LUTRATIO ); glVertex2f( .5, 270.*LUTRATIO ); glVertex2f( .5, 310.*LUTRATIO ); glEnd(); for ( i=1; ix-DIMPOINT, upoint->y-DIMPOINT ); glVertex2f( upoint->x-DIMPOINT, upoint->y+DIMPOINT ); glVertex2f( upoint->x+DIMPOINT, upoint->y-DIMPOINT ); glVertex2f( upoint->x+DIMPOINT, upoint->y+DIMPOINT ); glEnd(); /* Tangente -------- */ tg = &upoint->tg; if (upoint->last ? upoint->last->mode == POLYNOMIAL : 0) { glBegin( GL_LINES ); glVertex2f( tg->x0, tg->y0 ); glVertex2f( upoint->x, upoint->y ); glEnd(); glBegin( GL_LINE_LOOP ); glVertex2f( tg->x0-DIMPOINT, tg->y0-DIMPOINT ); glVertex2f( tg->x0-DIMPOINT, tg->y0+DIMPOINT ); glVertex2f( tg->x0+DIMPOINT, tg->y0+DIMPOINT ); glVertex2f( tg->x0+DIMPOINT, tg->y0-DIMPOINT ); glEnd(); } if (upoint->mode == POLYNOMIAL) { glBegin( GL_LINES ); glVertex2f( upoint->x, upoint->y ); glVertex2f( tg->x1, tg->y1 ); glEnd(); glBegin( GL_LINE_LOOP ); glVertex2f( tg->x1-DIMPOINT, tg->y1-DIMPOINT ); glVertex2f( tg->x1-DIMPOINT, tg->y1+DIMPOINT ); glVertex2f( tg->x1+DIMPOINT, tg->y1+DIMPOINT ); glVertex2f( tg->x1+DIMPOINT, tg->y1-DIMPOINT ); glEnd(); } } while ( (upoint=upoint->next) != NULL ); /* Highlight current point ----------------------- */ ndx = curPoint->x; h = curPoint->y; switch (curCmpnt) { case 3: glColor3f(1.,1.,1.); break; case 2: glColor3f(0.,0.,1.); break; case 1: glColor3f(0.,1.,0.); break; case 0: glColor3f(1.,0.,0.); break; } glBegin( GL_LINE_LOOP ); glVertex2f( (float)ndx-2.*DIMPOINT, h-2.*DIMPOINT ); glVertex2f( (float)ndx-2.*DIMPOINT, h+2.*DIMPOINT ); glVertex2f( (float)ndx+2.*DIMPOINT, h+2.*DIMPOINT ); glVertex2f( (float)ndx+2.*DIMPOINT, h-2.*DIMPOINT ); glEnd(); } else { float x, y; OrthoTransform( Mousex, Mousey, &x, &y ); ndx = (int) SUP( INF(x,(float)MAXNDX), 0 ); } /* Coordinates text string ----------------------- */ glColor3f( 0., 0., 0. ); sprintf( string, "%.5d: rgba %.3f %.3f %.3f %.3f", ndx, TabCmpnt(0,ndx), TabCmpnt(1,ndx), TabCmpnt(2,ndx), TabCmpnt(3,ndx) ); output( LUTRATIO, 257.*LUTRATIO, string ); glutSwapBuffers(); } /*---------------------------------------------------------------------------* * YACME_pick *---------------------------------------------------------------------------*/ void YACME_pick( int mousex, int mousey, PickObject *obj ) { int cmpnt, i, priority[4]; float x, y, val; Tangente *tg; UserPoint *upoint; float pickrad; obj->type = -1; OrthoTransform( mousex, mousey, &x, &y ); /* On travaille en priorite sur les objets definis par l'utilisateur ----------------------------------------------------------------- */ for ( i=0; i=0; i--, cmpnt=priority[i] ) if ( DrawCurve[cmpnt] ) { upoint = userPoint[cmpnt]; while ( upoint != NULL ) { /* On cherche le POINT */ if ( ABS(y-upoint->y) < pickrad && ABS(x-upoint->x) < pickrad ) { obj->upoint = upoint; obj->cmpnt = cmpnt; obj->type = POINT; return; } /* On cherche la demi-tangente GAUCHE */ tg = &upoint->tg; if ( ABS(x-tg->x0) < pickrad && ABS(y-tg->y0) < pickrad ) { obj->upoint = upoint; obj->cmpnt = cmpnt; obj->type = LEFT_TAN; return; } /* On cherche la demi-tangente DROITE */ if ( ABS(x-tg->x1) < pickrad && ABS(y-tg->y1) < pickrad ) { obj->upoint = upoint; obj->cmpnt = cmpnt; obj->type = RIGHT_TAN; return; } upoint = upoint->next; } /* Puis on cherche les coordonnees sur la CURVE (On considere la precision suffisante pour le picking suivant l'axe X) Remarque : on ne sort pas en ce cas, car la priorite est sur les objets utilisateurs. */ upoint = userPoint[cmpnt]; while ( upoint->next->x < x ) { upoint = upoint->next; if ( upoint->next == NULL ) return; } val = INF( SUP( Polynome4(x,upoint->polynome), 0.), (float)MAXNDX ); if ( ABS(y-val) < pickrad ) { obj->cmpnt = cmpnt; obj->ndx = ((x-(int)x)<.5) ? (int)x : (int)x+1; obj->type = CURVE; return; } } } /*---------------------------------------------------------------------------* * YACME_update *---------------------------------------------------------------------------*/ void YACME_update( int cmpnt, UserPoint *upoint ) { int i; float val, t0, t1; Tangente *tg; tg = &upoint->tg; if ( tg->x1 != tg->x0 ) { t0 = (tg->y1-tg->y0) / (tg->x1-tg->x0); } else { t0 = (tg->y1-tg->y0)*10000.; } TabCmpnt(cmpnt,(int) upoint->x) = upoint->y/(float)MAXNDX; if ( upoint->last != NULL ) { tg = &upoint->last->tg; if ( tg->x1 != tg->x0 ) { t1 = (tg->y1-tg->y0) / (tg->x1-tg->x0); } else { t1 = (tg->y1-tg->y0)*10000.; } GetPolynome( upoint->last->mode, upoint->last->x, upoint->last->y, t1, upoint->x, upoint->y, t0, upoint->last->polynome ); for ( i=1+(int) upoint->last->x; i<(int) upoint->x; i++ ) { val = Polynome4((float) i, upoint->last->polynome)/(float)MAXNDX; TabCmpnt(cmpnt,i) = INF( SUP(val,0.), 1. ); } } if ( upoint->next != NULL ) { tg = &upoint->next->tg; if ( tg->x1 != tg->x0 ) { t1 = (tg->y1-tg->y0) / (tg->x1-tg->x0); } else { t1 = (tg->y1-tg->y0)*10000.; } GetPolynome( upoint->mode, upoint->x, upoint->y, t0, upoint->next->x, upoint->next->y, t1, upoint->polynome ); for ( i=1+(int) upoint->x; i<(int) upoint->next->x; i++ ) { val = Polynome4( (float) i, upoint->polynome )/(float)MAXNDX; TabCmpnt(cmpnt,i) = INF( SUP(val,0.), 1. ); } TabCmpnt(cmpnt,(int) upoint->next->x) = upoint->next->y/(float)MAXNDX; } } /*---------------------------------------------------------------------------* * freePointList *---------------------------------------------------------------------------*/ static void freePointList( UserPoint *upoint ) { while (upoint != NULL) { UserPoint *unext = upoint->next; freePoint( upoint ); upoint = unext; } } /*---------------------------------------------------------------------------* * clonePointList *---------------------------------------------------------------------------*/ static UserPoint * clonePointList( UserPoint *base ) { UserPoint *clone, *upoint; if (base == NULL) return NULL; newPoint( clone ); upoint = clone; memcpy( upoint, base, sizeof(UserPoint) ); upoint->last = NULL; upoint->next = NULL; while (base->next != NULL) { base = base->next; newPoint( upoint->next ); memcpy( upoint->next, base, sizeof(UserPoint) ); upoint->next->last = upoint; upoint->next->next = NULL; upoint = upoint->next; } return clone; } /*---------------------------------------------------------------------------* * ApplyCMap *---------------------------------------------------------------------------*/ void ApplyCMap(void) { int i; for (i=0; i<4; i++) if ( modifiedCurve[i] ) { freePointList( userPointSvg[i] ); userPointSvg[i] = clonePointList( userPoint[i] ); modifiedCurve[i] = 0; } } /*---------------------------------------------------------------------------* * ResetCMap *---------------------------------------------------------------------------*/ void ResetCMap(void) { int i; UserPoint *upoint; for (i=0; i<4; i++) if ( modifiedCurve[i] ) { freePointList( userPoint[i] ); userPoint[i] = clonePointList( userPointSvg[i] ); modifiedCurve[i] = 0; for (upoint=userPoint[i]; upoint!=NULL; upoint=upoint->next ) YACME_update( i, upoint ); } } /*---------------------------------------------------------------------------* * InsertPoint *---------------------------------------------------------------------------*/ int InsertPoint( PickObject *obj ) { float dx, dy, slope, coeff[4]; int i; Tangente *tg; UserPoint *upoint, *userpoint; upoint = userPoint[obj->cmpnt]; while ( (int) upoint->next->x <= obj->ndx ) { upoint = upoint->next; if ( upoint->next == NULL ) return 0; } if ( (int) upoint->x == obj->ndx ) { obj->upoint = upoint; return POINT; } newPoint( userpoint ); userpoint->x = (float) obj->ndx; userpoint->y = Polynome4( obj->ndx, upoint->polynome ); userpoint->y = SUP( INF(userpoint->y, (float)MAXNDX), 0. ); userpoint->mode = upoint->mode; for ( i=0; i<4; i++ ) { userpoint->polynome[i] = upoint->polynome[i]; } userpoint->next = upoint->next; userpoint->last = upoint; upoint->next = userpoint; userpoint->next->last = userpoint; /* calcul de slope = P'(index) --------------------------- */ if ( userpoint->y == (float)MAXNDX || userpoint->y == 0. ) { dx = 25.; dy = 0.; } else { coeff[0] = userpoint->polynome[0]*3.; coeff[1] = userpoint->polynome[1]*2.; coeff[2] = userpoint->polynome[2]; slope = coeff[0]; for (i=1; i<3; i++) { slope *= (float) obj->ndx; slope += coeff[i]; } /* Rappel : cos( arctg(x) ) = 1/sqr( 1 + x^2 ); sin( arctg(x) ) = |x|/sqr( 1 + x^2 ); */ dx = 25. / fsqrt( slope*slope + 1. ); dy = dx*slope; } dx *= LUTRATIO; dy *= LUTRATIO; tg = &userpoint->tg; tg->x0 = userpoint->x - dx; tg->x1 = userpoint->x + dx; tg->y0 = userpoint->y - dy; tg->y1 = userpoint->y + dy; obj->upoint = userpoint; return POINT; } /*---------------------------------------------------------------------------* * DeletePoint *---------------------------------------------------------------------------*/ void DeletePoint( int cmpnt, UserPoint *upoint ) { if ( upoint == NULL || upoint->last == NULL || upoint->next == NULL ) return; upoint->last->next = upoint->next; upoint->next->last = upoint->last; YACME_update( cmpnt, upoint->last ); freePoint( upoint ); } /*---------------------------------------------------------------------------* * MovePoint *---------------------------------------------------------------------------*/ int MovePoint( int mousex, int mousey ) { float x, y, dx, dy, minx, maxx; OrthoTransform( mousex, mousey, &x, &y ); y = SUP( INF(y,(float)MAXNDX), 0. ); x = ((x-(int)x)<.5) ? (float)(int)x : (float)(int)(x+1); y = ((y-(int)y)<.5) ? (float)(int)y : (float)(int)(y+1); if ( curPoint->next != NULL && curPoint->last!= NULL ) { minx = curPoint->last->x + 1.; maxx = curPoint->next->x - 1.; x = SUP( INF(x, maxx), minx ); dx = (float)x - curPoint->x; curPoint->x = (float) x; curPoint->tg.x0 += (float) dx; curPoint->tg.x1 += (float) dx; } dy = (float)y - curPoint->y; curPoint->y = (float)y; curPoint->tg.y0 += (float) dy; curPoint->tg.y1 += (float) dy; return 1; } /*---------------------------------------------------------------------------* * MoveTangente *---------------------------------------------------------------------------*/ int MoveTangente( int sens, int mousex, int mousey ) { float x, y, dx, dy, slope; Tangente *tg; OrthoTransform( mousex, mousey, &x, &y ); if ( sens == -1 ) { x = INF(x, curPoint->x); } else { x = SUP(x, curPoint->x); } if ( x != curPoint->x ) { slope = (curPoint->y - y); slope /= (curPoint->x - x); dx = 25. / fsqrt( slope*slope + 1. ); dy = dx*slope; } else { dx = 0.; dy = (curPoint->y < y) ? sens*25. : -sens*25.; } dx *= LUTRATIO; dy *= LUTRATIO; tg = &curPoint->tg; tg->x0 = curPoint->x; tg->y0 = curPoint->y; if ( curPoint->last != NULL ) { tg->x0 -= dx; tg->y0 -= dy; } tg->x1 = curPoint->x; tg->y1 = curPoint->y; if ( curPoint->next != NULL ) { tg->x1 += dx; tg->y1 += dy; } return 1; } /*---------------------------------------------------------------------------* * GetPolynome *---------------------------------------------------------------------------*/ /* we want a polynom P(x) = Ax^3 + Bx^2 + Cx + D so that : P(a0) = b0, P'(a0) = t0, P(a1) = b1, P'(a1) = t1 i.e. | a0^3 a0^2 a0 1 | |A| |b0| | a1^3 a1^2 a1 1 | |B| = |b1| | 3a0^2 2a0 1 0 | |C| |t0| | 3a1^2 2a1 1 0 | |D| |t1| */ void GetPolynome( int mode, float a0, float b0, float t0, float a1, float b1, float t1, float coeff[4] ) { Matrix mat, INV_mat; int i; float val; switch (mode) { case CONSTANT: /* we want P(x) = b0 */ coeff[0] = 0.; coeff[1] = 0.; coeff[2] = 0.; coeff[3] = b0; break; case LINEAR: /* we want P(x) = b0 + (x-a0)/(a1-a0)*(b1-b0) i.e. P(x) = x*[(b1-b0)/(a1-a0)] + b0 - a0*[(b1-b0)/(a1-a0)] */ val = (b1-b0)/(a1-a0); coeff[0] = 0.; coeff[1] = 0.; coeff[2] = val; coeff[3] = b0 - a0*val; break; case POLYNOMIAL: /* we want a polynom P(x) = Ax^3 + Bx^2 + Cx + D so that : P(a0) = b0, P'(a0) = t0, P(a1) = b1, P'(a1) = t1 i.e. | a0^3 a0^2 a0 1 | |A| |b0| | a1^3 a1^2 a1 1 | |B| = |b1| | 3a0^2 2a0 1 0 | |C| |t0| | 3a1^2 2a1 1 0 | |D| |t1| */ val = 1.; for (i=3; i>=0; i--) { mat[0][i] = val; val *= a0; } val = 1.; for (i=3; i>=0; i--) { mat[1][i] = val; val *= a1; } mat[2][3] = 0.; mat[2][2] = 1.; mat[2][1] = 2.*a0; mat[2][0] = 3.*a0*a0; mat[3][3] = 0.; mat[3][2] = 1.; mat[3][1] = 2.*a1; mat[3][0] = 3.*a1*a1; invertmat( mat, INV_mat ); for (i=0; i<4; i++) coeff[i] = INV_mat[i][0]*b0 + INV_mat[i][1]*b1 + INV_mat[i][2]*t0 + INV_mat[i][3]*t1; break; } } /*---------------------------------------------------------------------------* * OrthoTransform *---------------------------------------------------------------------------*/ void OrthoTransform( int mx, int my, float *x, float *y ) { float xf, yf; xf = (float) mx; xf /= (float) W; xf *= (float) (RIGHT - LEFT); xf += (float) LEFT; yf = (float) my; yf /= (float) H; yf *= (float) (TOP - BOTTOM); yf += (float) BOTTOM; *x = xf; *y = yf; } /*---------------------------------------------------------------------------* * Polynome4 *---------------------------------------------------------------------------*/ float Polynome4( float x, float *coeff ) { int j; float val = coeff[0]; for (j=1; j<4; j++) { val *= x; val += coeff[j]; } return val; } /*---------------------------------------------------------------------------* * MAIN *---------------------------------------------------------------------------*/ #ifdef YACME_DBG #include "RGBA.h" int main( int argc, char *argv[] ) { glutInit( &argc, argv ); YACME_init( 0, 0, WINWIDTH, WINHEIGHT, 256, (float**)RGBA, NULL, NULL ); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ } #endif