gradtool
diff gradtool.c @ 0:960cea2731c4
gradtool hg import (used to be in subversion, fuck subversion)
author | John Tsiombikas <nuclear@mutantstargoat.com> |
---|---|
date | Tue, 19 Jun 2012 05:30:45 +0300 |
parents | |
children | c438411b801b |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gradtool.c Tue Jun 19 05:30:45 2012 +0300 1.3 @@ -0,0 +1,419 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <GL/glut.h> 1.7 + 1.8 +#define MAX_POS 512 1.9 + 1.10 +typedef struct key { 1.11 + int pos; 1.12 + float val; 1.13 + struct key *next; 1.14 +} key_t; 1.15 + 1.16 +struct track { 1.17 + key_t *keys; 1.18 + int count; 1.19 +}; 1.20 + 1.21 +void redraw(void); 1.22 +void draw_curves(void); 1.23 +void draw_grad(void); 1.24 + 1.25 +void set_val(struct track *track, float pos, float val); 1.26 +void rm_val(struct track *track, float pos); 1.27 +float get_val(struct track *track, float pos); 1.28 + 1.29 +void save(void); 1.30 + 1.31 +void key_handler(unsigned char key, int x, int y); 1.32 +void skey_handler(int key, int x, int y); 1.33 +void mbutton_handler(int bn, int state, int x, int y); 1.34 +void drag_handler(int x, int y); 1.35 +void reshape_handler(int x, int y); 1.36 + 1.37 +int view_xsz = 640; 1.38 +int view_ysz = 480; 1.39 + 1.40 +struct track tred, tgreen, tblue; 1.41 + 1.42 +int main(int argc, char **argv) 1.43 +{ 1.44 + glutInit(&argc, argv); 1.45 + glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE); 1.46 + glutInitWindowSize(view_xsz, view_ysz); 1.47 + glutCreateWindow("Mindlapse gradiant editor"); 1.48 + 1.49 + glutDisplayFunc(redraw); 1.50 + glutKeyboardFunc(key_handler); 1.51 + glutSpecialFunc(skey_handler); 1.52 + glutMouseFunc(mbutton_handler); 1.53 + glutMotionFunc(drag_handler); 1.54 + glutReshapeFunc(reshape_handler); 1.55 + 1.56 + glClearColor(0, 0, 0, 0); 1.57 + glEnable(GL_POINT_SMOOTH); 1.58 + 1.59 + glMatrixMode(GL_PROJECTION); 1.60 + glOrtho(0, 1, 0, 1, -1, 1); 1.61 + glMatrixMode(GL_MODELVIEW); 1.62 + 1.63 + tred.keys = malloc(sizeof *tred.keys); 1.64 + tred.keys->next = 0; 1.65 + 1.66 + tgreen.keys = malloc(sizeof *tgreen.keys); 1.67 + tgreen.keys->next = 0; 1.68 + 1.69 + tblue.keys = malloc(sizeof *tblue.keys); 1.70 + tblue.keys->next = 0; 1.71 + 1.72 + glutMainLoop(); 1.73 + return 0; 1.74 +} 1.75 + 1.76 +void redraw(void) 1.77 +{ 1.78 + glClear(GL_COLOR_BUFFER_BIT); 1.79 + 1.80 + draw_curves(); 1.81 + 1.82 + draw_grad(); 1.83 + 1.84 + glutSwapBuffers(); 1.85 +} 1.86 + 1.87 +void draw_curves(void) 1.88 +{ 1.89 + int i; 1.90 + key_t *ptr; 1.91 + 1.92 + glLoadIdentity(); 1.93 + glTranslatef(0, 0.25, 0); 1.94 + glScalef(1, 0.75, 1); 1.95 + 1.96 + glBegin(GL_LINES); 1.97 + /* draw grid */ 1.98 + glColor3f(0.5, 0.5, 0.5); 1.99 + glVertex2f(0, 0); glVertex2f(0, 1); 1.100 + glVertex2f(1, 0); glVertex2f(1, 1); 1.101 + glVertex2f(0, 0); glVertex2f(1, 0); 1.102 + glVertex2f(0, 1); glVertex2f(1, 1); 1.103 + 1.104 + glVertex2f(0, 0.25); glVertex2f(1, 0.25); 1.105 + glVertex2f(0, 0.5); glVertex2f(1, 0.5); 1.106 + glVertex2f(0, 0.75); glVertex2f(1, 0.75); 1.107 + 1.108 + glVertex2f(0.25, 0); glVertex2f(0.25, 1); 1.109 + glVertex2f(0.5, 0); glVertex2f(0.5, 1); 1.110 + glVertex2f(0.75, 0); glVertex2f(0.75, 1); 1.111 + glEnd(); 1.112 + 1.113 + glEnable(GL_BLEND); 1.114 + glBlendFunc(GL_ONE, GL_ONE); 1.115 + 1.116 + glBegin(GL_LINES); 1.117 + for(i=0; i<3; i++) { 1.118 + glColor3f(i == 0, i == 1, i == 2); 1.119 + ptr = (i == 0 ? tred.keys->next : (i == 1 ? tgreen.keys->next : tblue.keys->next)); 1.120 + 1.121 + if(ptr && ptr->pos > 0) { 1.122 + glVertex2f(0, ptr->val); 1.123 + glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); 1.124 + } 1.125 + 1.126 + while(ptr && ptr->next) { 1.127 + glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); 1.128 + glVertex2f(ptr->next->pos / (float)MAX_POS, ptr->next->val); 1.129 + ptr = ptr->next; 1.130 + } 1.131 + 1.132 + if(ptr && ptr->pos != MAX_POS) { 1.133 + glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); 1.134 + glVertex2f(1, ptr->val); 1.135 + } 1.136 + } 1.137 + glEnd(); 1.138 + 1.139 + glPointSize(5); 1.140 + glBegin(GL_POINTS); 1.141 + for(i=0; i<3; i++) { 1.142 + glColor3f(i == 0, i == 1, i == 2); 1.143 + ptr = (i == 0 ? tred.keys->next : (i == 1 ? tgreen.keys->next : tblue.keys->next)); 1.144 + 1.145 + while(ptr) { 1.146 + glVertex2f(ptr->pos / (float)MAX_POS, ptr->val); 1.147 + ptr = ptr->next; 1.148 + } 1.149 + } 1.150 + glEnd(); 1.151 + 1.152 + glDisable(GL_BLEND); 1.153 +} 1.154 + 1.155 +#define GRAD_SAMPLES MAX_POS 1.156 +void draw_grad(void) 1.157 +{ 1.158 + int i; 1.159 + 1.160 + glLoadIdentity(); 1.161 + glScalef(1, 0.25, 1); 1.162 + 1.163 + glBegin(GL_QUADS); 1.164 + for(i=0; i<GRAD_SAMPLES-1; i++) { 1.165 + float t = (float)i / (float)GRAD_SAMPLES; 1.166 + glColor3f(get_val(&tred, t), get_val(&tgreen, t), get_val(&tblue, t)); 1.167 + glVertex2f(t, 0); 1.168 + glVertex2f(t, 1); 1.169 + 1.170 + t = (float)(i + 1) / (float)GRAD_SAMPLES; 1.171 + glColor3f(get_val(&tred, t), get_val(&tgreen, t), get_val(&tblue, t)); 1.172 + glVertex2f(t, 1); 1.173 + glVertex2f(t, 0); 1.174 + } 1.175 + glEnd(); 1.176 +} 1.177 + 1.178 +void set_val(struct track *tr, float pos, float val) 1.179 +{ 1.180 + key_t *nkey; 1.181 + key_t *ptr = tr->keys; 1.182 + int ipos = (int)(pos * MAX_POS); 1.183 + 1.184 + if(!ptr->next || ptr->next->pos > ipos) { 1.185 + nkey = malloc(sizeof *nkey); 1.186 + nkey->pos = ipos; 1.187 + nkey->val = val; 1.188 + nkey->next = ptr->next; 1.189 + ptr->next = nkey; 1.190 + return; 1.191 + } 1.192 + 1.193 + while(ptr->next && ptr->next->pos < ipos) { 1.194 + ptr = ptr->next; 1.195 + } 1.196 + 1.197 + if(ptr->pos == ipos) { 1.198 + ptr->val = val; 1.199 + } else { 1.200 + nkey = malloc(sizeof *nkey); 1.201 + nkey->pos = ipos; 1.202 + nkey->val = val; 1.203 + nkey->next = ptr->next; 1.204 + ptr->next = nkey; 1.205 + } 1.206 +} 1.207 + 1.208 +void rm_val(struct track *tr, float pos) 1.209 +{ 1.210 + key_t *ptr = tr->keys; 1.211 + int ipos = (int)(pos * MAX_POS); 1.212 + 1.213 + while(ptr->next && ptr->next->pos <= ipos) { 1.214 + if(ptr->next->pos == ipos) { 1.215 + key_t *tmp = ptr->next; 1.216 + ptr->next = ptr->next->next; 1.217 + free(tmp); 1.218 + return; 1.219 + } 1.220 + ptr = ptr->next; 1.221 + } 1.222 +} 1.223 + 1.224 +float get_val(struct track *tr, float pos) 1.225 +{ 1.226 + float t; 1.227 + key_t *ptr = tr->keys->next; 1.228 + int ipos = (int)(pos * MAX_POS); 1.229 + 1.230 + if(!ptr) { 1.231 + return 0.0; 1.232 + } 1.233 + 1.234 + while(ptr && ptr->pos <= ipos) { 1.235 + if(ptr->pos == ipos || !ptr->next) { 1.236 + return ptr->val; 1.237 + } 1.238 + 1.239 + if(ptr->next->pos > ipos) { 1.240 + t = (float)(ipos - ptr->pos) / (float)(ptr->next->pos - ptr->pos); 1.241 + return ptr->val + (ptr->next->val - ptr->val) * t; 1.242 + } 1.243 + 1.244 + ptr = ptr->next; 1.245 + } 1.246 + 1.247 + return tr->keys->next->val; 1.248 +} 1.249 + 1.250 +void clear_track(struct track *tr) 1.251 +{ 1.252 + key_t *ptr = tr->keys->next; 1.253 + while(ptr) { 1.254 + key_t *tmp = ptr; 1.255 + ptr = ptr->next; 1.256 + free(tmp); 1.257 + } 1.258 + tr->keys->next = 0; 1.259 +} 1.260 + 1.261 + 1.262 +#define IMG_X 256 1.263 +#define FNAME "grad.ppm" 1.264 +void save(void) 1.265 +{ 1.266 + int i; 1.267 + FILE *fp; 1.268 + 1.269 + if(!(fp = fopen(FNAME, "wb"))) { 1.270 + perror("failed to write " FNAME); 1.271 + return; 1.272 + } 1.273 + 1.274 + fprintf(fp, "P6\n%d %d\n255\n", IMG_X, 1); 1.275 + 1.276 + for(i=0; i<IMG_X; i++) { 1.277 + float t = (float)i / (float)IMG_X; 1.278 + int r = get_val(&tred, t) * 255.0; 1.279 + int g = get_val(&tgreen, t) * 255.0; 1.280 + int b = get_val(&tblue, t) * 255.0; 1.281 + 1.282 + fputc(r, fp); 1.283 + fputc(g, fp); 1.284 + fputc(b, fp); 1.285 + } 1.286 + 1.287 + fclose(fp); 1.288 +} 1.289 + 1.290 + 1.291 +void key_handler(unsigned char key, int x, int y) 1.292 +{ 1.293 + skey_handler(key, x, y); 1.294 +} 1.295 + 1.296 +void skey_handler(int key, int x, int y) 1.297 +{ 1.298 + switch(key) { 1.299 + case 27: 1.300 + exit(0); 1.301 + 1.302 + case 's': 1.303 + case 'S': 1.304 + save(); 1.305 + break; 1.306 + 1.307 + case 'c': 1.308 + clear_track(&tred); 1.309 + clear_track(&tgreen); 1.310 + clear_track(&tblue); 1.311 + glutPostRedisplay(); 1.312 + break; 1.313 + 1.314 + default: 1.315 + break; 1.316 + } 1.317 +} 1.318 + 1.319 +static int px, py; 1.320 +static float ppos, pval; 1.321 +static struct track *tr; 1.322 + 1.323 +void mbutton_handler(int bn, int state, int x, int y) 1.324 +{ 1.325 + float pos, val; 1.326 + 1.327 + pos = (float)x / (float)view_xsz; 1.328 + val = 1.0 - (float)y / (float)(view_ysz - view_ysz / 4.0); 1.329 + 1.330 + if(bn == GLUT_LEFT_BUTTON) { 1.331 + tr = &tred; 1.332 + } else if(bn == GLUT_MIDDLE_BUTTON) { 1.333 + tr = &tgreen; 1.334 + } else if(bn == GLUT_RIGHT_BUTTON) { 1.335 + tr = &tblue; 1.336 + } else { 1.337 + return; 1.338 + } 1.339 + 1.340 + if(glutGetModifiers() & GLUT_ACTIVE_CTRL) { 1.341 + tr = 0; 1.342 + } 1.343 + 1.344 + if(state == 0) { 1.345 + px = x; 1.346 + py = y; 1.347 + ppos = pos; 1.348 + pval = val; 1.349 + } else { 1.350 + if(px == -1 || abs(x - px) > 2 || abs(y - py) > 2) { 1.351 + return; 1.352 + } 1.353 + if(val < 0.0 || val > 1.0) return; 1.354 + 1.355 + 1.356 + if(glutGetModifiers() & GLUT_ACTIVE_SHIFT) { 1.357 + if(tr) { 1.358 + rm_val(tr, pos); 1.359 + } else { 1.360 + rm_val(&tred, pos); 1.361 + rm_val(&tgreen, pos); 1.362 + rm_val(&tblue, pos); 1.363 + } 1.364 + } else { 1.365 + if(tr) { 1.366 + set_val(tr, pos, val); 1.367 + } else { 1.368 + set_val(&tred, pos, val); 1.369 + set_val(&tgreen, pos, val); 1.370 + set_val(&tblue, pos, val); 1.371 + } 1.372 + } 1.373 + 1.374 + px = -1; 1.375 + py = -1; 1.376 + glutPostRedisplay(); 1.377 + } 1.378 +} 1.379 + 1.380 +void drag_handler(int x, int y) 1.381 +{ 1.382 + float pos = (float)x / (float)view_xsz; 1.383 + float val = 1.0 - (float)y / (float)(view_ysz - view_ysz / 4.0); 1.384 + 1.385 + if(pos < 0.0) pos = 0.0; 1.386 + if(pos > 1.0) pos = 1.0; 1.387 + if(val < 0.0) val = 0.0; 1.388 + if(val > 1.0) val = 1.0; 1.389 + 1.390 + if(tr) { 1.391 + rm_val(tr, ppos); 1.392 + rm_val(tr, ppos - 1.0 / (float)view_xsz); 1.393 + rm_val(tr, ppos + 1.0 / (float)view_xsz); 1.394 + set_val(tr, pos, val); 1.395 + } else { 1.396 + rm_val(&tred, ppos); 1.397 + rm_val(&tgreen, ppos); 1.398 + rm_val(&tblue, ppos); 1.399 + rm_val(&tred, ppos - 1.0 / (float)view_xsz); 1.400 + rm_val(&tgreen, ppos - 1.0 / (float)view_xsz); 1.401 + rm_val(&tblue, ppos - 1.0 / (float)view_xsz); 1.402 + rm_val(&tred, ppos + 1.0 / (float)view_xsz); 1.403 + rm_val(&tgreen, ppos + 1.0 / (float)view_xsz); 1.404 + rm_val(&tblue, ppos + 1.0 / (float)view_xsz); 1.405 + set_val(&tred, pos, val); 1.406 + set_val(&tgreen, pos, val); 1.407 + set_val(&tblue, pos, val); 1.408 + } 1.409 + 1.410 + ppos = pos; 1.411 + pval = val; 1.412 + 1.413 + glutPostRedisplay(); 1.414 +} 1.415 + 1.416 +void reshape_handler(int x, int y) 1.417 +{ 1.418 + view_xsz = x; 1.419 + view_ysz = y; 1.420 + 1.421 + glViewport(0, 0, x, y); 1.422 +}