home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Computerworld 1996 March
/
Computerworld_1996-03_cd.bin
/
idg_cd3
/
grafika
/
fraktaly
/
frasr192
/
stereo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-26
|
10KB
|
364 lines
/*
STEREO.C a module to view 3D images.
Written in Borland 'C++' by Paul de Leeuw.
From an idea in "New Scientist" 9 October 1993 pages 26 - 29.
Change History:
11 June 94 - Modified to reuse existing Fractint arrays TW
11 July 94 - Added depth parameter PDL
14 July 94 - Added grayscale option and did general cleanup TW
19 July 94 - Fixed negative depth PDL
19 July 94 - Added calibration bars, get_min_max() TW
24 Sep 94 - Added image save/restore, color cycle, and save TW
28 Sep 94 - Added image map TW
20 Mar 95 - Fixed endless loop bug with bad depth values TW
23 Mar 95 - Allow arbitrary dimension image maps TW
(TW is Tim Wegner, PDL is Paul de Leeuw)
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include "fractint.h"
#include "prototyp.h"
#include "helpdefs.h"
char stereomapname[81] = {""};
int AutoStereo_depth = 100;
double AutoStereo_width = 10;
char grayflag = 0; /* flag to use gray value rather than color
* number */
char calibrate = 1; /* add calibration bars to image */
char image_map = 0;
/* this structure permits variables to be temporarily static and visible
to routines in this file without permanently hogging memory */
static struct static_vars
{
long avg;
long avgct;
long depth;
int barheight;
int ground;
int maxcc;
int maxc;
int minc;
int reverse;
int sep;
double width;
int x1;
int x2;
int xcen;
int y;
int y1;
int y2;
int ycen;
BYTE *savedac;
} *pv;
#define AVG (pv->avg)
#define AVGCT (pv->avgct)
#define DEPTH (pv->depth)
#define BARHEIGHT (pv->barheight)
#define GROUND (pv->ground)
#define MAXCC (pv->maxcc)
#define MAXC (pv->maxc)
#define MINC (pv->minc)
#define REVERSE (pv->reverse)
#define SEP (pv->sep)
#define WIDTH (pv->width)
#define X1 (pv->x1)
#define X2 (pv->x2)
#define Y (pv->y)
#define Y1 (pv->y1)
#define Y2 (pv->y2)
#define XCEN (pv->xcen)
#define YCEN (pv->ycen)
/*
The getdepth() function allows using the grayscale value of the color
as DEPTH, rather than the color number. Maybe I got a little too
sophisticated trying to avoid a divide, so the comment tells what all
the multiplies and shifts are trying to do. The result should be from
0 to 255.
*/
typedef BYTE (*DACBOX)[256][3];
#define dac (*((DACBOX)(pv->savedac)))
static int getdepth(int xd, int yd)
{
int pal;
pal = getcolor(xd, yd);
if (grayflag)
{
/* effectively (30*R + 59*G + 11*B)/100 scaled 0 to 255 */
pal = ((int) dac[pal][0] * 77 +
(int) dac[pal][1] * 151 +
(int) dac[pal][2] * 28);
pal >>= 6;
}
return (pal);
}
/*
Get min and max DEPTH value in picture
*/
static int get_min_max(void)
{
int xd, yd, ldepth;
MINC = colors;
MAXC = 0;
for(yd = 0; yd < ydots; yd++)
{
if (keypressed())
return (1);
if(yd == 20)
showtempmsg("Getting min and max");
for(xd = 0; xd < xdots; xd++)
{
ldepth = getdepth(xd,yd);
if ( ldepth < MINC)
MINC = ldepth;
if (ldepth > MAXC)
MAXC = ldepth;
}
}
cleartempmsg();
return(0);
}
void toggle_bars(int *bars, int barwidth, int far *colour)
{
int i, j, ct;
find_special_colors();
ct = 0;
for (i = XCEN; i < (XCEN) + barwidth; i++)
for (j = YCEN; j < (YCEN) + BARHEIGHT; j++)
{
if(*bars)
{
putcolor(i + (int)(AVG), j , color_bright);
putcolor(i - (int)(AVG), j , color_bright);
}
else
{
putcolor(i + (int)(AVG), j, colour[ct++]);
putcolor(i - (int)(AVG), j, colour[ct++]);
}
}
*bars = 1 - *bars;
}
int outline_stereo(BYTE * pixels, int linelen)
{
int i, j, x, s;
int far *same;
int far *colour;
if((Y) >= ydots)
return(1);
same = (int far *)MK_FP(extraseg,0);
colour = &same[ydots];
for (x = 0; x < xdots; ++x)
same[x] = x;
for (x = 0; x < xdots; ++x)
{
if(REVERSE)
SEP = GROUND - (int) (DEPTH * (getdepth(x, Y) - MINC) / MAXCC);
else
SEP = GROUND - (int) (DEPTH * (MAXCC - (getdepth(x, Y) - MINC)) / MAXCC);
SEP = (int)((SEP * 10.0) / WIDTH); /* adjust for media WIDTH */
/* get average value under calibration bars */
if(X1 <= x && x <= X2 && Y1 <= Y && Y <= Y2)
{
AVG += SEP;
(AVGCT)++;
}
i = x - (SEP + (SEP & Y & 1)) / 2;
j = i + SEP;
if (0 <= i && j < xdots)
{
/* there are cases where next never terminates so we timeout */
int ct = 0;
for (s = same[i]; s != i && s != j && ct++ < xdots; s = same[i])
{
if (s > j)
{
same[i] = j;
i = j;
j = s;
}
else
i = s;
}
same[i] = j;
}
}
for (x = xdots - 1; x >= 0; x--)
{
if (same[x] == x)
/* colour[x] = rand()%colors; */
colour[x] = (int)pixels[x%linelen];
else
colour[x] = colour[same[x]];
putcolor(x, Y, colour[x]);
}
(Y)++;
return(0);
}
/**************************************************************************
Convert current image into Auto Stereo Picture
**************************************************************************/
int do_AutoStereo(void)
{
struct static_vars v;
BYTE savedacbox[256*3];
int oldhelpmode, ret=0;
int i, j, done;
int bars, ct, kbdchar, barwidth;
time_t ltime;
unsigned char *buf = (unsigned char *)decoderline;
/* int same[MAXPIXELS],colour[MAXPIXELS] */
/* following two lines re-use existing arrays in Fractint */
int far *same;
int far *colour;
same = (int far *)MK_FP(extraseg,0);
colour = &same[ydots];
pv = &v; /* set static vars to stack structure */
pv->savedac = savedacbox;
/* Use the current time to randomize the random number sequence. */
time(<ime);
srand((unsigned int)ltime);
oldhelpmode = helpmode;
helpmode = RDSKEYS;
savegraphics(); /* save graphics image */
memcpy(savedacbox, dacbox, 256 * 3); /* save colors */
/* empircally determined adjustment to make WIDTH scale correctly */
WIDTH = AutoStereo_width*.67;
if(WIDTH < 1)
WIDTH = 1;
GROUND = xdots / 8;
if(AutoStereo_depth < 0)
REVERSE = 1;
else
REVERSE = 0;
DEPTH = ((long) xdots * (long) AutoStereo_depth) / 4000L;
DEPTH = labs(DEPTH) + 1;
if(get_min_max())
{
buzzer(1);
ret = 1;
goto exit_stereo;
}
MAXCC = MAXC - MINC + 1;
AVG = AVGCT = 0L;
barwidth = 1 + xdots / 200;
BARHEIGHT = 1 + ydots / 20;
XCEN = xdots/2;
if(calibrate > 1)
YCEN = BARHEIGHT/2;
else
YCEN = ydots/2;
/* box to average for calibration bars */
X1 = XCEN - xdots/16;
X2 = XCEN + xdots/16;
Y1 = YCEN - BARHEIGHT/2;
Y2 = YCEN + BARHEIGHT/2;
Y = 0;
if(image_map)
{
outln = outline_stereo;
while((Y) < ydots)
if(gifview())
{
ret = 1;
goto exit_stereo;
}
}
else
{
while(Y < ydots)
{
if(keypressed())
{
ret = 1;
goto exit_stereo;
}
for(i=0;i<xdots;i++)
buf[i] = (unsigned char)(rand()%colors);
outline_stereo(buf,xdots);
}
}
find_special_colors();
AVG /= AVGCT;
AVG /= 2;
ct = 0;
for (i = XCEN; i < XCEN + barwidth; i++)
for (j = YCEN; j < YCEN + BARHEIGHT; j++)
{
colour[ct++] = getcolor(i + (int)(AVG), j);
colour[ct++] = getcolor(i - (int)(AVG), j);
}
if(calibrate)
bars = 1;
else
bars = 0;
toggle_bars(&bars, barwidth, colour);
done = 0;
while(done==0)
{
while(keypressed()==0); /* to trap F1 key */
kbdchar = getakey();
switch(kbdchar)
{
case ENTER: /* toggle bars */
case SPACE:
toggle_bars(&bars, barwidth, colour);
break;
case 'c':
case '+':
case '-':
rotate((kbdchar == 'c') ? 0 : ((kbdchar == '+') ? 1 : -1));
break;
case 's':
diskisactive = 1; /* flag for disk-video routines */
savetodisk(savename);
diskisactive = 0;
break;
default:
if(kbdchar == 27) /* if ESC avoid returning to menu */
kbdchar = 255;
ungetakey(kbdchar);
buzzer(0);
done = 1;
break;
}
}
exit_stereo:
helpmode = oldhelpmode;
restoregraphics();
memcpy(dacbox, savedacbox, 256 * 3);
spindac(0,1);
return (ret);
}