nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: nuclear@0: #define MAX_POS 512 nuclear@0: nuclear@0: typedef struct key { nuclear@0: int pos; nuclear@0: float val; nuclear@0: struct key *next; nuclear@0: } key_t; nuclear@0: nuclear@0: struct track { nuclear@0: key_t *keys; nuclear@0: int count; nuclear@0: }; nuclear@0: nuclear@0: void redraw(void); nuclear@0: void draw_curves(void); nuclear@0: void draw_grad(void); nuclear@0: nuclear@0: void set_val(struct track *track, float pos, float val); nuclear@0: void rm_val(struct track *track, float pos); nuclear@0: float get_val(struct track *track, float pos); nuclear@0: nuclear@0: void save(void); nuclear@0: nuclear@0: void key_handler(unsigned char key, int x, int y); nuclear@0: void skey_handler(int key, int x, int y); nuclear@0: void mbutton_handler(int bn, int state, int x, int y); nuclear@0: void drag_handler(int x, int y); nuclear@0: void reshape_handler(int x, int y); nuclear@0: nuclear@0: int view_xsz = 640; nuclear@0: int view_ysz = 480; nuclear@0: nuclear@0: struct track tred, tgreen, tblue; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: glutInit(&argc, argv); nuclear@0: glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); nuclear@0: glutInitWindowSize(view_xsz, view_ysz); nuclear@0: glutCreateWindow("Mindlapse gradiant editor"); nuclear@0: nuclear@0: glutDisplayFunc(redraw); nuclear@0: glutKeyboardFunc(key_handler); nuclear@0: glutSpecialFunc(skey_handler); nuclear@0: glutMouseFunc(mbutton_handler); nuclear@0: glutMotionFunc(drag_handler); nuclear@0: glutReshapeFunc(reshape_handler); nuclear@0: nuclear@0: glClearColor(0, 0, 0, 0); nuclear@0: glEnable(GL_POINT_SMOOTH); nuclear@0: nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glOrtho(0, 1, 0, 1, -1, 1); nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: nuclear@0: tred.keys = malloc(sizeof *tred.keys); nuclear@0: tred.keys->next = 0; nuclear@0: nuclear@0: tgreen.keys = malloc(sizeof *tgreen.keys); nuclear@0: tgreen.keys->next = 0; nuclear@0: nuclear@0: tblue.keys = malloc(sizeof *tblue.keys); nuclear@0: tblue.keys->next = 0; nuclear@0: nuclear@0: glutMainLoop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: void redraw(void) nuclear@0: { nuclear@0: glClear(GL_COLOR_BUFFER_BIT); nuclear@0: nuclear@0: draw_curves(); nuclear@0: nuclear@0: draw_grad(); nuclear@0: nuclear@0: glutSwapBuffers(); nuclear@0: } nuclear@0: nuclear@0: void draw_curves(void) nuclear@0: { nuclear@0: int i; nuclear@0: key_t *ptr; nuclear@0: nuclear@0: glLoadIdentity(); nuclear@0: glTranslatef(0, 0.25, 0); nuclear@0: glScalef(1, 0.75, 1); nuclear@0: nuclear@0: glBegin(GL_LINES); nuclear@0: /* draw grid */ nuclear@0: glColor3f(0.5, 0.5, 0.5); nuclear@0: glVertex2f(0, 0); glVertex2f(0, 1); nuclear@0: glVertex2f(1, 0); glVertex2f(1, 1); nuclear@0: glVertex2f(0, 0); glVertex2f(1, 0); nuclear@0: glVertex2f(0, 1); glVertex2f(1, 1); nuclear@0: nuclear@0: glVertex2f(0, 0.25); glVertex2f(1, 0.25); nuclear@0: glVertex2f(0, 0.5); glVertex2f(1, 0.5); nuclear@0: glVertex2f(0, 0.75); glVertex2f(1, 0.75); nuclear@0: nuclear@0: glVertex2f(0.25, 0); glVertex2f(0.25, 1); nuclear@0: glVertex2f(0.5, 0); glVertex2f(0.5, 1); nuclear@0: glVertex2f(0.75, 0); glVertex2f(0.75, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: glEnable(GL_BLEND); nuclear@0: glBlendFunc(GL_ONE, GL_ONE); nuclear@0: nuclear@0: glBegin(GL_LINES); nuclear@0: for(i=0; i<3; i++) { nuclear@0: glColor3f(i == 0, i == 1, i == 2); nuclear@0: ptr = (i == 0 ? tred.keys->next : (i == 1 ? tgreen.keys->next : tblue.keys->next)); nuclear@0: nuclear@0: if(ptr && ptr->pos > 0) { nuclear@0: glVertex2f(0, ptr->val); nuclear@0: glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); nuclear@0: } nuclear@0: nuclear@0: while(ptr && ptr->next) { nuclear@0: glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); nuclear@0: glVertex2f(ptr->next->pos / (float)MAX_POS, ptr->next->val); nuclear@0: ptr = ptr->next; nuclear@0: } nuclear@0: nuclear@0: if(ptr && ptr->pos != MAX_POS) { nuclear@0: glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); nuclear@0: glVertex2f(1, ptr->val); nuclear@0: } nuclear@0: } nuclear@0: glEnd(); nuclear@0: nuclear@0: glPointSize(5); nuclear@0: glBegin(GL_POINTS); nuclear@0: for(i=0; i<3; i++) { nuclear@0: glColor3f(i == 0, i == 1, i == 2); nuclear@0: ptr = (i == 0 ? tred.keys->next : (i == 1 ? tgreen.keys->next : tblue.keys->next)); nuclear@0: nuclear@0: while(ptr) { nuclear@0: glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); nuclear@0: ptr = ptr->next; nuclear@0: } nuclear@0: } nuclear@0: glEnd(); nuclear@0: nuclear@0: glDisable(GL_BLEND); nuclear@0: } nuclear@0: nuclear@0: #define GRAD_SAMPLES MAX_POS nuclear@0: void draw_grad(void) nuclear@0: { nuclear@0: int i; nuclear@0: nuclear@0: glLoadIdentity(); nuclear@0: glScalef(1, 0.25, 1); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: for(i=0; ikeys; nuclear@0: int ipos = (int)(pos * MAX_POS); nuclear@0: nuclear@0: if(!ptr->next || ptr->next->pos > ipos) { nuclear@0: nkey = malloc(sizeof *nkey); nuclear@0: nkey->pos = ipos; nuclear@0: nkey->val = val; nuclear@0: nkey->next = ptr->next; nuclear@0: ptr->next = nkey; nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: while(ptr->next && ptr->next->pos < ipos) { nuclear@0: ptr = ptr->next; nuclear@0: } nuclear@0: nuclear@0: if(ptr->pos == ipos) { nuclear@0: ptr->val = val; nuclear@0: } else { nuclear@0: nkey = malloc(sizeof *nkey); nuclear@0: nkey->pos = ipos; nuclear@0: nkey->val = val; nuclear@0: nkey->next = ptr->next; nuclear@0: ptr->next = nkey; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void rm_val(struct track *tr, float pos) nuclear@0: { nuclear@0: key_t *ptr = tr->keys; nuclear@0: int ipos = (int)(pos * MAX_POS); nuclear@0: nuclear@0: while(ptr->next && ptr->next->pos <= ipos) { nuclear@0: if(ptr->next->pos == ipos) { nuclear@0: key_t *tmp = ptr->next; nuclear@0: ptr->next = ptr->next->next; nuclear@0: free(tmp); nuclear@0: return; nuclear@0: } nuclear@0: ptr = ptr->next; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: float get_val(struct track *tr, float pos) nuclear@0: { nuclear@0: float t; nuclear@0: key_t *ptr = tr->keys->next; nuclear@0: int ipos = (int)(pos * MAX_POS); nuclear@0: nuclear@0: if(!ptr) { nuclear@0: return 0.0; nuclear@0: } nuclear@0: nuclear@0: while(ptr && ptr->pos <= ipos) { nuclear@0: if(ptr->pos == ipos || !ptr->next) { nuclear@0: return ptr->val; nuclear@0: } nuclear@0: nuclear@0: if(ptr->next->pos > ipos) { nuclear@0: t = (float)(ipos - ptr->pos) / (float)(ptr->next->pos - ptr->pos); nuclear@0: return ptr->val + (ptr->next->val - ptr->val) * t; nuclear@0: } nuclear@0: nuclear@0: ptr = ptr->next; nuclear@0: } nuclear@0: nuclear@0: return tr->keys->next->val; nuclear@0: } nuclear@0: nuclear@0: void clear_track(struct track *tr) nuclear@0: { nuclear@0: key_t *ptr = tr->keys->next; nuclear@0: while(ptr) { nuclear@0: key_t *tmp = ptr; nuclear@0: ptr = ptr->next; nuclear@0: free(tmp); nuclear@0: } nuclear@0: tr->keys->next = 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: #define IMG_X 256 nuclear@0: #define FNAME "grad.ppm" nuclear@0: void save(void) nuclear@0: { nuclear@0: int i; nuclear@0: FILE *fp; nuclear@0: nuclear@0: if(!(fp = fopen(FNAME, "wb"))) { nuclear@0: perror("failed to write " FNAME); nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: fprintf(fp, "P6\n%d %d\n255\n", IMG_X, 1); nuclear@0: nuclear@0: for(i=0; i 2 || abs(y - py) > 2) { nuclear@0: return; nuclear@0: } nuclear@0: if(val < 0.0 || val > 1.0) return; nuclear@0: nuclear@0: nuclear@0: if(glutGetModifiers() & GLUT_ACTIVE_SHIFT) { nuclear@0: if(tr) { nuclear@0: rm_val(tr, pos); nuclear@0: } else { nuclear@0: rm_val(&tred, pos); nuclear@0: rm_val(&tgreen, pos); nuclear@0: rm_val(&tblue, pos); nuclear@0: } nuclear@0: } else { nuclear@0: if(tr) { nuclear@0: set_val(tr, pos, val); nuclear@0: } else { nuclear@0: set_val(&tred, pos, val); nuclear@0: set_val(&tgreen, pos, val); nuclear@0: set_val(&tblue, pos, val); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: px = -1; nuclear@0: py = -1; nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: void drag_handler(int x, int y) nuclear@0: { nuclear@0: float pos = (float)x / (float)view_xsz; nuclear@0: float val = 1.0 - (float)y / (float)(view_ysz - view_ysz / 4.0); nuclear@0: nuclear@0: if(pos < 0.0) pos = 0.0; nuclear@0: if(pos > 1.0) pos = 1.0; nuclear@0: if(val < 0.0) val = 0.0; nuclear@0: if(val > 1.0) val = 1.0; nuclear@0: nuclear@0: if(tr) { nuclear@0: rm_val(tr, ppos); nuclear@0: rm_val(tr, ppos - 1.0 / (float)view_xsz); nuclear@0: rm_val(tr, ppos + 1.0 / (float)view_xsz); nuclear@0: set_val(tr, pos, val); nuclear@0: } else { nuclear@0: rm_val(&tred, ppos); nuclear@0: rm_val(&tgreen, ppos); nuclear@0: rm_val(&tblue, ppos); nuclear@0: rm_val(&tred, ppos - 1.0 / (float)view_xsz); nuclear@0: rm_val(&tgreen, ppos - 1.0 / (float)view_xsz); nuclear@0: rm_val(&tblue, ppos - 1.0 / (float)view_xsz); nuclear@0: rm_val(&tred, ppos + 1.0 / (float)view_xsz); nuclear@0: rm_val(&tgreen, ppos + 1.0 / (float)view_xsz); nuclear@0: rm_val(&tblue, ppos + 1.0 / (float)view_xsz); nuclear@0: set_val(&tred, pos, val); nuclear@0: set_val(&tgreen, pos, val); nuclear@0: set_val(&tblue, pos, val); nuclear@0: } nuclear@0: nuclear@0: ppos = pos; nuclear@0: pval = val; nuclear@0: nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: void reshape_handler(int x, int y) nuclear@0: { nuclear@0: view_xsz = x; nuclear@0: view_ysz = y; nuclear@0: nuclear@0: glViewport(0, 0, x, y); nuclear@0: }