/* * smartdraw.c: Dibuja funciones matemáticas y representa * superficies de relieve a partir de bumpmaps BMP. * Copyright (c) Gonzalo J. Carracedo 2008 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */ #include #include #include #include #include #include #include expr_t *expr; unsigned char gradient [4608]; void SDL_DrawLine(SDL_Surface *screen, int x1, int y1, int x2, int y2, Uint8 Rc, Uint8 Gc, Uint8 Bc){ Uint32 color = SDL_MapRGB(screen->format, Rc, Gc, Bc); int dx, dy, dx2, dy2; int sx, sy; int i, l; int e; if( (x1 < 0) | (screen->w <= x1) | (x2 < 0) | (screen->w <= x2) | (y1 < 0) | (screen->h <= y1) | (y2 < 0) | (screen->h <= y2)) return; if(SDL_MUSTLOCK(screen)){ if(SDL_LockSurface(screen) < 0){ return; } } dx = x2 - x1 < 0 ? x1 - x2 : x2 - x1; dy = y2 - y1 < 0 ? y1 - y2 : y2 - y1; sx = x2 - x1 < 0 ? -1 : 1; sy = y2 - y1 < 0 ? -1 : 1; dx2 = dx * 2; dy2 = dy * 2; if(x1 == x2){ if(y1 < y2){ for(i = y1;i < y2;i++){ pset_abs (x1, i, color); } } else{ for(i = y2;i < y1;i++){ pset_abs (x1, i, color); } } } else if(y1 == y2){ if(x1 < x2){ for(i = x1;i < x2;i++){ pset_abs (i, y1, color); } } else{ for(i = x2;i < x1;i++){ pset_abs (i, y1, color); } } } else if(dx >= dy){ e = -dx; l = (dx + 1) / 2; for(i = 0;i < l;i++){ pset_abs (x1, y1, color); pset_abs (x2, y2, color); x1 += sx; x2 -= sx; e += dy2; if(e >= 0){ y1 += sy; y2 -= sy; e -= dx2; } } if(dx % 2 == 0) pset_abs (x1, y1, color); } else{ e = -dy; l = (dy + 1) / 2; for(i = 0;i < l;i++){ pset_abs (x1, y1, color); pset_abs (x2, y2, color); y1 += sy; y2 -= sy; e += dx2; if(e >= 0){ x1 += sx; x2 -= sx; e -= dy2; } } if(dy % 2 == 0) pset_abs (x1, y1, color); } if(SDL_MUSTLOCK(screen)){ SDL_UnlockSurface(screen); } } #define ZOOM 150.0 #define MIDDLE_X (SURFACE_WIDTH / 2) #define MIDDLE_Y (SURFACE_HEIGHT / 2) #define SINE_OF_PI_SIXTHS 0.5 #define COSINE_OF_PI_SIXTHS 0.86602540378444 double t = -2.0; #define PHI 1.822875655532295295 #define SQRT_OF_5 2.236067977499789696 //inline double calc_function (double x, double y) //{ //return 40 * sin (x*x + y*y - t); //return 100 * sqrt (5 - x*x - y*y); //register double r = sqrt(x*x + y*y); // register double r = sqrt (x*x + ; //return 100 * (sin(sqrt((x*x + y*y)) + 10*t)); //return 2*ZOOM*((sqrt (36 - x*x - y*y) + tanh (-(x*x + y*y) * t))); //return 2 * ZOOM * (sin (sqrt (x*x + y*y) - t*10)); //return 2 * ZOOM * cimag (cpow (PHI, sqrt (x*x + y*y) - t) - cpow (-PHI, - sqrt (x*x + y*y) + t)) / SQRT_OF_5; //return ZOOM * sin (x*x + y*y - t * 10); // return ZOOM * (pow (sin(x * 2 + t * 10), 8.0) * pow (sin(y * 2 - t * 10), 8.0)); // return 2 * ZOOM * sin (sqrt (x*x + y*y) - 10 * t); //} inline double calc_function_inverse (double x, double y) { //return 40 * sin (x*x + y*y - t); //return -calc_function (x, y); return 0; } double dx, dy; inline void paint_pix (double x, double y, int color) { register int rx, ry, xx, xy, yx, yy; register double f; dx = x / ZOOM; dy = y / ZOOM; /* Tenemos que transformar las bases canónicas. Ahora son vectores orientados 30 grados respecto de la horizontal. */ xx = x * COSINE_OF_PI_SIXTHS; xy = x * SINE_OF_PI_SIXTHS; yx = - y * COSINE_OF_PI_SIXTHS; /* Recordemos que Y es perpendicular a X */ yy = y * SINE_OF_PI_SIXTHS; f = 2 * ZOOM * praslan_eval (expr); /* Sumamos ambos vectores y tenemos el punto resultante */ rx = MIDDLE_X + xx + yx; ry = MIDDLE_Y + xy + yy - SINE_OF_PI_SIXTHS * f; pset_abs (rx, ry, color * calc_color (100 * f / ZOOM + 1768)); // f = calc_function_inverse (dx, dy); // ry = MIDDLE_Y + xy + yy - SINE_OF_PI_SIXTHS * f; // // pset_abs (rx, ry, color * calc_color (2 * f + 1768)); //SDL_DrawLine (screen, rx, ry + 1, rx, MIDDLE_Y + 150 * SINE_OF_PI_SIXTHS, 0, 0, 0); } int last_point_x, last_point_y; int reset; inline void paint_pix_bump (double x, double y, double height) { register int rx, ry, xx, xy, yx, yy; register double f; dx = x / ZOOM; dy = y / ZOOM; /* Tenemos que transformar las bases canónicas. Ahora son vectores orientados 30 grados respecto de la horizontal. */ xx = x * COSINE_OF_PI_SIXTHS; xy = x * SINE_OF_PI_SIXTHS; yx = - y * COSINE_OF_PI_SIXTHS; /* Recordemos que Y es perpendicular a X */ yy = y * SINE_OF_PI_SIXTHS; f = 4 * (height); /* Sumamos ambos vectores y tenemos el punto resultante */ rx = MIDDLE_X + xx + yx; ry = MIDDLE_Y + xy + yy - SINE_OF_PI_SIXTHS * f / 20.0; if (reset) { pset_abs (rx, ry, calc_color (- 220 * f / ZOOM + 1600)); reset = 0; } else eline (last_point_x, last_point_y, rx, ry, calc_color_grad (- 220 * f / ZOOM + 1536, gradient)); last_point_x = rx; last_point_y = ry; // f = calc_function_inverse (dx, dy); // ry = MIDDLE_Y + xy + yy - SINE_OF_PI_SIXTHS * f; // // pset_abs (rx, ry, color * calc_color (2 * f + 1768)); // //SDL_DrawLine (screen, rx, ry + 1, rx, MIDDLE_Y + 150 * SINE_OF_PI_SIXTHS, 0, 0, 0); } void paint_scale () { double i; char msg [256]; for (i = 0; i < 256; i += 0.5) eline (256 + (int) (i * 2), 700, 256 + (int) (i * 2), 720, calc_color_grad (-880.0 * i / (double) ZOOM + 1536, gradient)); eline (256, 700, 256, 720, 0xffffff); eline (256, 700, 767, 700, 0xffffff); eline (767, 700, 767, 720, 0xffffff); eline (256, 720, 768, 720, 0xffffff); for (i = 0; i < 257; i += 32) { if (i == 0) strcpy (msg, "MIN"); else if (i == 256) strcpy (msg, "MAX"); else sprintf (msg, "+%g", i); eputs (msg, 256 + (int) i * 2, 725, 0xffffff, 0); } eputs ("Escala fuera de unidades standard, tan solo en el rango BMP de valores (0 - 255)", 256, 750, 0xffffff, 0); redraw (); } #define START -300 #define END 300 int main (int argc, char **argv) { FILE *fp, *gradfp; int color = 0; char swp; register double i, j; int n; complex im = I; char w[200]; if (argc < 2) { fprintf (stderr, "Forma de uso: %s [-b fichero.bmp [gradiente24bits.bmp]] | \n", argv[0]); exit (1); } if (strcmp (argv[1], "-b") == 0) { if (argc < 3) { fprintf (stderr, "Forma de uso: %s [-b fichero.bmp [gradiente24bits.bmp]] | \n", argv[0]); exit (1); } fp = fopen (argv[2], "rb"); if (fp == NULL) { perror (argv[2]); exit (2); } if (argc == 3) { for (n = 0; n < 1536; n++) { color = calc_color (n + 1536); memcpy (&gradient[n * 3], &color, 3); swp = gradient[n * 3]; gradient[n * 3] = gradient[n * 3 + 2]; gradient[n * 3 + 2] = swp; } } else { gradfp = fopen (argv[3], "rb"); if (gradfp == NULL) { fprintf (stderr, "%s; Fichero de gradiente no encontrado.\n", argv[3]); exit (1); } fseek (gradfp, 54, SEEK_SET); fread (gradient, 1536 * 3, 1, gradfp); fclose (gradfp); } /* Supone un cuadro de 600 x 600, así que */ init_egraph (); SDL_WM_SetCaption ("Mapa de relieve superficial", "3D Window"); paint_scale (); for (i = START ; i < END; i += 0.1) { reset = 1; for (j = START; j < END; j += 0.1) { fseek (fp, 54 + (((int) i + 300) * 600 + ((int) j + 300)) * 3, SEEK_SET); fread (&color, 3, 1, fp); paint_pix_bump (j, i, color & 0xff); } redraw_fast (); } end_egraph (); } expr = praslan_new (argv[1], 4, "x", &dx, "y", &dy, "t", &t, "i", &im); if (expr == NULL) exit (1); init_egraph (); SDL_WM_SetCaption ("Funciones de dos variables con colores de nivel", "3D Window"); while(1) { sprintf (w, "%s; t = %lg ", argv[1], t); eputs (w, 1, 1, 0xffffff, 0); for (i = START ; i < END; i += 4) for (j = START; j < END; j += 1) paint_pix (i, j, 1); redraw (); for (i = START ; i < END; i += 4) for (j = START; j < END; j += 1) paint_pix (i, j, 0); t += 0.01; } end_egraph (); }