home *** CD-ROM | disk | FTP | other *** search
/ Computerworld 1996 March / Computerworld_1996-03_cd.bin / idg_cd3 / grafika / fraktaly / frasr192 / stereo.c < prev    next >
C/C++ Source or Header  |  1995-03-26  |  10KB  |  364 lines

  1. /*
  2.     STEREO.C a module to view 3D images.
  3.     Written in Borland 'C++' by Paul de Leeuw.
  4.     From an idea in "New Scientist" 9 October 1993 pages 26 - 29.
  5.  
  6.     Change History:
  7.       11 June 94 - Modified to reuse existing Fractint arrays        TW
  8.       11 July 94 - Added depth parameter                             PDL
  9.       14 July 94 - Added grayscale option and did general cleanup    TW
  10.       19 July 94 - Fixed negative depth                              PDL
  11.       19 July 94 - Added calibration bars, get_min_max()             TW
  12.       24 Sep  94 - Added image save/restore, color cycle, and save   TW
  13.       28 Sep  94 - Added image map                                   TW
  14.       20 Mar  95 - Fixed endless loop bug with bad depth values      TW
  15.       23 Mar  95 - Allow arbitrary dimension image maps              TW
  16.       
  17.       (TW is Tim Wegner, PDL is Paul de Leeuw)
  18. */
  19.  
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdlib.h>
  23. #include <time.h>
  24. #include "fractint.h"
  25. #include "prototyp.h"
  26. #include "helpdefs.h"
  27.  
  28. char stereomapname[81] = {""};
  29. int AutoStereo_depth = 100;
  30. double AutoStereo_width = 10;
  31. char grayflag = 0;              /* flag to use gray value rather than color
  32.                                  * number */
  33. char calibrate = 1;             /* add calibration bars to image */
  34. char image_map = 0;
  35.  
  36. /* this structure permits variables to be temporarily static and visible
  37.    to routines in this file without permanently hogging memory */
  38.  
  39. static struct static_vars 
  40. {
  41.    long avg;
  42.    long avgct;
  43.    long depth;
  44.    int barheight;
  45.    int ground;
  46.    int maxcc;
  47.    int maxc;
  48.    int minc;
  49.    int reverse;
  50.    int sep;
  51.    double width;
  52.    int x1;
  53.    int x2;
  54.    int xcen;
  55.    int y;
  56.    int y1;
  57.    int y2;
  58.    int ycen;
  59.    BYTE *savedac;
  60. } *pv;
  61.  
  62. #define AVG         (pv->avg)
  63. #define AVGCT       (pv->avgct)
  64. #define DEPTH       (pv->depth)
  65. #define BARHEIGHT   (pv->barheight)
  66. #define GROUND      (pv->ground)
  67. #define MAXCC       (pv->maxcc)
  68. #define MAXC        (pv->maxc)
  69. #define MINC        (pv->minc)
  70. #define REVERSE     (pv->reverse)
  71. #define SEP         (pv->sep)
  72. #define WIDTH       (pv->width)
  73. #define X1          (pv->x1)
  74. #define X2          (pv->x2)
  75. #define Y           (pv->y)
  76. #define Y1          (pv->y1)
  77. #define Y2          (pv->y2)
  78. #define XCEN        (pv->xcen)
  79. #define YCEN        (pv->ycen)
  80.  
  81. /*
  82.    The getdepth() function allows using the grayscale value of the color
  83.    as DEPTH, rather than the color number. Maybe I got a little too
  84.    sophisticated trying to avoid a divide, so the comment tells what all
  85.    the multiplies and shifts are trying to do. The result should be from
  86.    0 to 255.
  87. */
  88.  
  89. typedef BYTE (*DACBOX)[256][3];
  90. #define dac   (*((DACBOX)(pv->savedac)))
  91.  
  92. static int getdepth(int xd, int yd)
  93. {
  94.    int pal;
  95.    pal = getcolor(xd, yd);
  96.    if (grayflag)
  97.    {
  98.       /* effectively (30*R + 59*G + 11*B)/100 scaled 0 to 255 */
  99.       pal = ((int) dac[pal][0] * 77 + 
  100.              (int) dac[pal][1] * 151 + 
  101.              (int) dac[pal][2] * 28);
  102.       pal >>= 6;
  103.    }
  104.    return (pal);
  105. }
  106.  
  107. /*
  108.    Get min and max DEPTH value in picture 
  109. */
  110.  
  111. static int get_min_max(void)
  112. {
  113.    int xd, yd, ldepth;
  114.    MINC = colors;
  115.    MAXC = 0;
  116.    for(yd = 0; yd < ydots; yd++)
  117.    {
  118.       if (keypressed())
  119.          return (1);
  120.       if(yd == 20)
  121.          showtempmsg("Getting min and max");
  122.       for(xd = 0; xd < xdots; xd++)
  123.       {
  124.          ldepth = getdepth(xd,yd);
  125.          if ( ldepth < MINC)
  126.             MINC = ldepth;
  127.          if (ldepth > MAXC)
  128.             MAXC = ldepth;   
  129.       }
  130.    }
  131.    cleartempmsg();   
  132.    return(0);
  133. }
  134.  
  135. void toggle_bars(int *bars, int barwidth, int far *colour)
  136. {
  137.    int i, j, ct;
  138.    find_special_colors();
  139.    ct = 0;
  140.    for (i = XCEN; i < (XCEN) + barwidth; i++)
  141.       for (j = YCEN; j < (YCEN) + BARHEIGHT; j++)
  142.       {
  143.          if(*bars)
  144.          {
  145.             putcolor(i + (int)(AVG), j , color_bright);
  146.             putcolor(i - (int)(AVG), j , color_bright);
  147.          }
  148.          else
  149.          {
  150.             putcolor(i + (int)(AVG), j, colour[ct++]);
  151.             putcolor(i - (int)(AVG), j, colour[ct++]);
  152.          }
  153.       }
  154.    *bars = 1 - *bars;
  155. }
  156.  
  157. int outline_stereo(BYTE * pixels, int linelen)
  158. {
  159.    int i, j, x, s; 
  160.    int far *same;
  161.    int far *colour;
  162.    if((Y) >= ydots)
  163.       return(1);
  164.    same   = (int far *)MK_FP(extraseg,0);
  165.    colour = &same[ydots];
  166.  
  167.    for (x = 0; x < xdots; ++x)
  168.       same[x] = x;
  169.    for (x = 0; x < xdots; ++x)
  170.    {
  171.       if(REVERSE)
  172.          SEP = GROUND - (int) (DEPTH * (getdepth(x, Y) - MINC) / MAXCC);
  173.       else
  174.          SEP = GROUND - (int) (DEPTH * (MAXCC - (getdepth(x, Y) - MINC)) / MAXCC);
  175.       SEP =  (int)((SEP * 10.0) / WIDTH);        /* adjust for media WIDTH */
  176.  
  177.       /* get average value under calibration bars */
  178.       if(X1 <= x && x <= X2 && Y1 <= Y && Y <= Y2)
  179.       {
  180.          AVG += SEP;
  181.          (AVGCT)++;
  182.       }
  183.       i = x - (SEP + (SEP & Y & 1)) / 2;
  184.       j = i + SEP;
  185.       if (0 <= i && j < xdots)
  186.       {
  187.          /* there are cases where next never terminates so we timeout */
  188.          int ct = 0; 
  189.          for (s = same[i]; s != i && s != j && ct++ < xdots; s = same[i])
  190.          {
  191.             if (s > j)
  192.             {
  193.                same[i] = j;
  194.                i = j;
  195.                j = s;
  196.             }
  197.             else
  198.                i = s;
  199.          }      
  200.          same[i] = j;
  201.       }
  202.    }
  203.    for (x = xdots - 1; x >= 0; x--)
  204.    {
  205.       if (same[x] == x)
  206.          /* colour[x] = rand()%colors; */
  207.          colour[x] = (int)pixels[x%linelen];
  208.       else
  209.          colour[x] = colour[same[x]];
  210.       putcolor(x, Y, colour[x]);
  211.    }
  212.    (Y)++;
  213.    return(0);
  214. }
  215.  
  216.  
  217. /**************************************************************************
  218.         Convert current image into Auto Stereo Picture
  219. **************************************************************************/
  220.  
  221. int do_AutoStereo(void)
  222. {
  223.    struct static_vars v;
  224.    BYTE savedacbox[256*3];
  225.    int oldhelpmode, ret=0;
  226.    int i, j, done;
  227.    int bars, ct, kbdchar, barwidth;
  228.    time_t ltime;
  229.    unsigned char *buf = (unsigned char *)decoderline;
  230.          
  231.    /* int same[MAXPIXELS],colour[MAXPIXELS] */
  232.  
  233.    /* following two lines re-use existing arrays in Fractint */
  234.    int far *same;
  235.    int far *colour;
  236.    same   = (int far *)MK_FP(extraseg,0);
  237.    colour = &same[ydots];
  238.    
  239.    pv = &v;   /* set static vars to stack structure */
  240.    pv->savedac = savedacbox;
  241.    
  242.    /* Use the current time to randomize the random number sequence. */
  243.    time(<ime);
  244.    srand((unsigned int)ltime);
  245.  
  246.    oldhelpmode = helpmode;
  247.    helpmode = RDSKEYS;
  248.    savegraphics();                      /* save graphics image */
  249.    memcpy(savedacbox, dacbox, 256 * 3);  /* save colors */
  250.  
  251.  
  252.    /* empircally determined adjustment to make WIDTH scale correctly */
  253.    WIDTH = AutoStereo_width*.67;
  254.    if(WIDTH < 1)
  255.       WIDTH = 1;
  256.    GROUND = xdots / 8;
  257.    if(AutoStereo_depth < 0)
  258.       REVERSE = 1;
  259.    else
  260.       REVERSE = 0;   
  261.    DEPTH = ((long) xdots * (long) AutoStereo_depth) / 4000L;
  262.    DEPTH = labs(DEPTH) + 1;
  263.    if(get_min_max())
  264.    {
  265.       buzzer(1);
  266.       ret = 1;
  267.       goto exit_stereo;
  268.    }
  269.    MAXCC = MAXC - MINC + 1;
  270.    AVG = AVGCT = 0L;
  271.    barwidth  = 1 + xdots / 200;
  272.    BARHEIGHT = 1 + ydots / 20;
  273.    XCEN = xdots/2;
  274.    if(calibrate > 1)
  275.       YCEN = BARHEIGHT/2;
  276.    else
  277.       YCEN = ydots/2;
  278.  
  279.    /* box to average for calibration bars */
  280.    X1 = XCEN - xdots/16;
  281.    X2 = XCEN + xdots/16;
  282.    Y1 = YCEN - BARHEIGHT/2;
  283.    Y2 = YCEN + BARHEIGHT/2;
  284.       
  285.    Y = 0;
  286.    if(image_map)
  287.    {
  288.       outln = outline_stereo;
  289.       while((Y) < ydots)
  290.          if(gifview())
  291.          {
  292.             ret = 1;
  293.             goto exit_stereo;
  294.          }   
  295.    }
  296.    else
  297.    {
  298.       while(Y < ydots)
  299.       {
  300.           if(keypressed())
  301.           {
  302.              ret = 1;
  303.              goto exit_stereo;
  304.           }
  305.           for(i=0;i<xdots;i++)
  306.              buf[i] = (unsigned char)(rand()%colors);
  307.           outline_stereo(buf,xdots);    
  308.       }
  309.    }   
  310.    
  311.    find_special_colors();
  312.    AVG /= AVGCT;   
  313.    AVG /= 2;
  314.    ct = 0;
  315.    for (i = XCEN; i < XCEN + barwidth; i++)
  316.       for (j = YCEN; j < YCEN + BARHEIGHT; j++)
  317.       {
  318.          colour[ct++] = getcolor(i + (int)(AVG), j);
  319.          colour[ct++] = getcolor(i - (int)(AVG), j);
  320.       }
  321.    if(calibrate)
  322.       bars = 1;
  323.    else
  324.       bars = 0;
  325.    toggle_bars(&bars, barwidth, colour);
  326.    done = 0;
  327.    while(done==0)
  328.    {
  329.       while(keypressed()==0); /* to trap F1 key */
  330.       kbdchar = getakey();
  331.       switch(kbdchar)
  332.       {
  333.          case ENTER:   /* toggle bars */
  334.          case SPACE:
  335.             toggle_bars(&bars, barwidth, colour);
  336.             break;
  337.          case 'c':
  338.          case '+':
  339.          case '-':
  340.             rotate((kbdchar == 'c') ? 0 : ((kbdchar == '+') ? 1 : -1));
  341.             break;
  342.          case 's':
  343.             diskisactive = 1;        /* flag for disk-video routines */
  344.             savetodisk(savename);
  345.             diskisactive = 0;    
  346.             break;
  347.          default:
  348.             if(kbdchar == 27)   /* if ESC avoid returning to menu */
  349.                kbdchar = 255;   
  350.             ungetakey(kbdchar);
  351.             buzzer(0);
  352.             done = 1;
  353.             break;   
  354.        }
  355.    }   
  356.  
  357.    exit_stereo:
  358.    helpmode = oldhelpmode;
  359.    restoregraphics();
  360.    memcpy(dacbox, savedacbox, 256 * 3);
  361.    spindac(0,1);
  362.    return (ret);
  363. }
  364.