/*************************************************************************************************************************************/
/* */
/* T O O L S F O R A U T O S T E R E O G R A M G E N E R A T I O N */
/* W I T H F L O A T I N G P O I N T D E P T H F I E L D : */
/* */
/* */
/* Example of an alpha-numeric autostereogram : */
/* */
/* */
/* O-oo::o:-o%o:o:-O-oo::o:-o%o:o:-O-oo::o:-o%o:o:-O-oo::o:-o%o:o:- */
/* -oo::O:.-::oOoo:-oo::O:.-::oOoo:-oo::O:.-::oOoo:-oo::O:.-::oOoo: */
/* :o:-OoO.-:OOo:o::o:-OoO.-:OOo:o::o:-OoO.-:OOo:o::o:-OoO.-:OOo:o: */
/* :o::::-OOOO-:oOo:o::::-OOOO-:oOo-o::::-OOOO-:oOo-o::::-OOOO-:oOo */
/* ::-o-o.o:oO:-oo-::-o-o.ooOo-oo-::-:::-::oOo-oo-::-:::-::oOo-oo-: */
/* :o-::oo::.:oo:Oo:o-::oo:.oooOo:o-::oo:.-ooo-%o:o-::oo:.-ooo-%o:o */
/* ::o-:O:o.o:ooooo::::O::o:o-oOo:--:%o-Ooo-ooO::::-:%o-Ooo-ooO:::: */
/* O-o-oOOoOOo:o:--oo-OOOOoooo:o:-oo-OO%O:oo::o-O-o-:OO%O:oo::o-O-o */
/* -o:-:o::oOo-::O-o::o:::OOo:-::O-o::o::oOo-::::o:-:o:::oOo-::::o: */
/* o-:-oO-o:ooo:o:-::oO::o::ooo:o:-::oO::o::oo::-:OoOOo-:o::oo::-:O */
/* :o-:::%::O:O-O:oo::::O%::O:O-O:oo::::O%::O:o%:.:::::o%%::O:o%:.: */
/* :-:::-oo::%-:-:-:o:::-oo::%-:-:-:o:::-oo::%-:--o:::--ooo::%-:--o */
/* :-o::Ooooo-:-%O-:OO-:Ooooo-:-%O-:OO-:Ooooo-:-O::O-oooooooo-:-O:: */
/* :::ooooOoOoo::o::-oooooOoOoo::o::-oooooOoOoo::o::o:OOoo%oOoo::o: */
/* o:oooo:::Ooo:-oo::oooo:::Ooo:-oo::oooo:::Ooo:-o:::o::::::Ooo:-o: */
/* :o::o::oO-:-.:::o:::o::oO-:-.:::o:::o::oO-:-.::o::o:::o:O-:-.::o */
/* o-oo:O::-oOoO-o:-ooo:O::-oOoO-o:-ooo:O::-oOoO-o-oo-Oo::--oOoO-o- */
/* o-o::oo:oo-::::-:oO::oo:oo-::::-:oO::oo:oo-:::::oo:OOoo:oo-::::: */
/* -o::-o:O-O-:oo-o::-:-o:O-O-:oo-o::-:-o:O-O-:ooo:-:-oo:oO-O-:ooo: */
/* O:Ooo:o:ooo:OoO:OOooo:o:ooo:OoO:OOooo:o:ooo:oo:%ooo::O::ooo:oo:% */
/* o:oO-o:oo::%Ooo:oO:-o::oo::%Ooo:oO:-o::oo:::ooOO--oo:::oo:::ooOO */
/* ::O:o-o:o::oO:-:o:o:-Oo:o::oO:-:o:o:-Oo:o:oO%:%oo:--:Oo:o:oO%:%o */
/* O.-:ooOOoo:ooo%O.:ooOO:ooo-Ooo%O.:oo%Oooo:oooo.-:ooO%Oooo:oooo.- */
/* O.o::-O:oo:o::o--o:.O:oo:o:o:O--o:.Ooo:o:o:O-O.o:o.Ooo:o:o:O-O.o */
/* oOO:-oo::oo%oo-:ooo-oo-ooOO:-o:oo-Oo:OooO:--ooOoo-Oo:OooO:--ooOo */
/* ooo:oO:Ooo:oo%o:ooo:o:OooO:#o:ooO:ooOoo-O:%%o:ooO:ooOoo-O:%%o:oo */
/* oo:ooo-o%-:%o:o:oo:ooo-OO-%ooo-oo:Oo:::%:-%ooo-oo:Oo:::%:-%ooo-o */
/* O:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oOO:O:o:o:%::Oo:oO */
/* Oo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-oOo:o:o:-Oo::oo-o */
/* ::::o::::o:ooO-O::::o::::o:ooO-O::::o::::o:ooO-O::::o::::o:ooO-O */
/* :o:-o::o-::::%Oo:o:-o::o-::::%Oo:o:-o::o-::::%Oo:o:-o::o-::::%Oo */
/* :o::::OO%-o::::.:o::::OO%-o::::.:o::::OO%-o::::.:o::::OO%-o::::. */
/* */
/* */
/* Author of '$xtc/stereogra.02$c' : */
/* */
/* Jean-Francois COLONNA (LACTAMME, 20110604100914). */
/* */
/*************************************************************************************************************************************/
#include <stdio.h>
extern void *malloc();
extern int atoi();
extern char *getenv();
#define Get(valeur_de_la_variable,nom_de_la_variable) \
{ \
valeur_de_la_variable = atoi(getenv(nom_de_la_variable)); \
} \
/* Get an environment variable. */
static int dimX=0;
#define Xmin 0
#define Xmax (Xmin + (dimX-1))
/* Definition of the 'OX' axis. */
static int dimY=0;
#define Ymin 0
#define Ymax (Ymin + (dimY-1))
/* Definition of the 'OY' axis. */
#define Dpicture(type,nom) \
type *nom=malloc(dimX*dimY*sizeof(type)) \
/* Definition of a picture as a matrix. */
#define Rpicture(type,nom) \
type *nom \
/* Reference a picture. */
#define IMAGE(image,x,y) \
(*(image + (int)((((y)-Ymin)*dimX) + ((x)-Xmin)))) \
/* Point access. */
#define COXR(x) \
((int)((x) - Xmin)) \
/* Relative value of an 'X' coordinate. */
#define COXA(x) \
((int)((x) + Xmin)) \
/* "Absolute" value of an 'X' coordinate. */
#define X_SCREEN(x) \
COXA((int)((double)(x)*((double)dimX))) \
/* Put a [0,1] value into X-screen coordinate system. */
#define X_01(x) \
((double)COXR(x)/(double)(dimX)) \
/* Put a [0,1] value into X-screen coordinate system. */
#define COYR(y) \
((int)((y) - Ymin)) \
/* Relative value of an 'Y' coordinate. */
#define COYA(y) \
((int)((y) + Ymin)) \
/* "Absolute" value of an 'Y' coordinate. */
#define Y_SCREEN(y) \
COYA((int)((double)(y)*((double)dimY))) \
/* Put a [0,1] value into Y-screen coordinate system. */
#define Y_01(y) \
((double)COYR(y)/(double)(dimY)) \
/* Put a [0,1] value into Y-screen coordinate system. */
#define LENG(origine,extremite) \
((int)((extremite)-(origine)+1)) \
/* Compute a length. */
#define MODS(x,origine,extremite) \
(((x) < (origine)) ? \
((x)-(((((x)+1-(origine))/LENG(origine,extremite))-1)*LENG(origine,extremite))) : \
(((x) > (origine)) ? \
((x)-((((x)-(origine))/LENG(origine,extremite))*LENG(origine,extremite))) : \
(x) \
) \
) \
/* Modulo. */
extern double atan2();
extern double sin();
extern double cos();
#define CERCLE_TRIGONOMETRIQUE \
6.283185307179586
#define COND(condition,valeur_si_VRAI,valeur_si_FAUX) \
((condition) ? (valeur_si_VRAI) : (valeur_si_FAUX))
#define IFNE(x,a) \
((x) != (a))
#define IFGE(x,a) \
((x) >= (a))
#define IZNE(x) \
IFNE(x,0)
#define IZGE(x) \
IFGE(x,0)
#define ADD2(a,b) \
((a) + (b))
#define SOUS(a,b) \
((a) - (b))
#define MUL2(a,b) \
((a) * (b))
#define DIVI(a,b) \
((a) / (b))
#define gSCAZ(x,ancien_intervalle,nouvel_intervalle,exception,conversion) \
COND(IZNE(ancien_intervalle) \
,MUL2(DIVI(conversion(x) \
,conversion(ancien_intervalle) \
) \
,conversion(nouvel_intervalle) \
) \
,exception \
)
#define SCAZ(x,ancien_intervalle,nouvel_intervalle,exception) \
gSCAZ(x,ancien_intervalle,nouvel_intervalle,exception,(double))
#define SCAL(x,ancien_intervalle,nouvel_intervalle) \
SCAZ(x,ancien_intervalle,nouvel_intervalle,x)
#define HOMO(x,origine1,extremite1,origine2,extremite2) \
ADD2(SCAL(SOUS(x,origine1),SOUS(extremite1,origine1),SOUS(extremite2,origine2)),origine2)
#define ATAN(y,x) \
COND(IZGE(atan2(y,x)),atan2(y,x),ADD2(CERCLE_TRIGONOMETRIQUE,atan2(y,x)))
#define CERC(x) \
ATAN(sin(x),cos(x))
#define MODF(x,origine,extremite) \
HOMO(CERC(HOMO(x \
,origine,extremite \
,0,CERCLE_TRIGONOMETRIQUE \
) \
) \
,0,CERCLE_TRIGONOMETRIQUE \
,origine,extremite \
)
/* Procedures utiles a 'fXmodulo(...)'. */
#define fXmodulo(x,period) \
MODF(x,0,period*(double)(dimX))
#define Xmodulo(x,period) \
COXA(MODS(COXR(x),COXR(Xmin),X_SCREEN(period)))
/* Put 'x' inside [Xmin,Xmin+period-1]. */
/*************************************************************************************************************************************/
/* */
/* A U T O S T E R E O G R A M G E N E R A T I O N : */
/* */
/*************************************************************************************************************************************/
Rpicture(unsigned char
,AutostereogramGeneration(Autostereogram,Depth,MultiplicativeFactor,Texture,IntrinsicPeriod,ActualPeriod,TextureSwap)
)
Rpicture(unsigned char,Autostereogram);
/* The autostereogram to be generated. */
Rpicture(double,Depth);
double MultiplicativeFactor;
/* The depth field of the scene to be displayed is defined itself as a picture ; high */
/* values correspond to points that are close to the viewer. */
Rpicture(unsigned char,Texture);
double IntrinsicPeriod;
double ActualPeriod;
/* The 2D texture to be used. Two periods are characteristic : */
/* */
/* 1-IntrinsicPeriod gives the intrinsic period of Texture ; for example, if Autostereogram */
/* should be made of 5 vertical bands, it is equal to 0.2 (=1/5). */
/* */
/* 2-ActualPeriod generally equals IntrinsicPeriod but it could be different in the case */
/* where texture is pseudo-periodical. It gives the width of the used area of Texture. */
int TextureSwap;
/* A logical indicator ; a null value allows the possible swap of texture points during */
/* the left shift process. This allows "dynamical" effects and for example "ghost" subsets */
/* of the 3D object that appear and disappear according to the point of view. */
{
Dpicture(double,Xshifted);
/* A temporary picture to simulate the process of circular shifting of Texture. */
int X,Y;
for (Y=Ymin ; Y<=Ymax ; Y++)
{
for (X=Xmin ; X<=Xmax ; X++)
{
IMAGE(Xshifted,X,Y) = Xmodulo(X,ActualPeriod);
}
}
for (Y=Ymin ; Y<=Ymax ; Y++)
{
int FormerLeftshift=0;
for (X=Xmin ; X<=Xmax ; X++)
{
double Leftshift=MultiplicativeFactor*IMAGE(Depth,X,Y);
double ActualLeftshift=((TextureSwap==0)||((FormerLeftshift-Leftshift)<=1)) ?
Leftshift :
FormerLeftshift-1;
/* Texture will be left circular shifted proportionally to the */
/* current Depth ; however, the actual left shift depends on */
/* the swapping enabling of the texture. */
int n;
for (n=1 ; n<=(ActualPeriod/IntrinsicPeriod) ; n++)
/* For the sake of simplicity it is assumed that IntrinsicPeriod */
/* divides exactly ActualPeriod. */
{
int Xperiodic=Xmodulo(X+(n-1)*X_SCREEN(IntrinsicPeriod),ActualPeriod);
IMAGE(Xshifted,Xmodulo(Xperiodic,ActualPeriod),Y)
= IMAGE(Xshifted,Xmodulo(Xperiodic+ActualLeftshift,ActualPeriod),Y);
/* shift the current texture according to the current depth. */
}
IMAGE(Autostereogram,X,Y)
= IMAGE(Texture,IMAGE(Xshifted,Xmodulo(X,ActualPeriod),Y),Y);
/* Generation of Autostereogram. */
FormerLeftshift = ActualLeftshift;
}
}
return(Autostereogram);
}
/*************************************************************************************************************************************/
/* */
/* M A I N T E S T P R O G R A M : */
/* */
/*************************************************************************************************************************************/
extern double exp();
extern double sin();
extern double drand48();
#define BLACK 0
#define WHITE 255
#define GreyLevel(n) \
(BLACK + ((n)*(WHITE-BLACK))) \
/* Convert a [-1,+1] value into a grey level. */
int main()
{
Get(dimX,"dimX");
Get(dimY,"dimY");
/* Get the definition of the picture size : */
/* */
/* setenv dimX ... */
/* setenv dimY ... */
/* */
{
Dpicture(unsigned char,Autostereogram);
/* The autostereogram to be generated. */
Dpicture(unsigned char,RealisticView);
Dpicture(double,DepthOfRealisticView);
int DepthChoice;
Dpicture(double,Depth);
double MultiplicativeFactor;
/* The depth field of the scene to be displayed is defined itself as a picture ; high */
/* values correspond to points that are close to the viewer. */
int TextureChoice;
Dpicture(unsigned char,Texture);
double IntrinsicPeriod;
double ActualPeriod;
/* The 2D texture to be used. Two periods are characteristic : */
/* */
/* 1-IntrinsicPeriod gives the intrinsic period of Texture ; for example, if Autostereogram */
/* should be made of 5 vertical bands, it is equal to 0.2 (=1/5). */
/* */
/* 2-ActualPeriod generally equals IntrinsicPeriod but it could be different in the case */
/* where texture is pseudo-periodical. It gives the width of the used area of Texture. */
int TextureSwap;
/* A logical indicator ; a null value allows the possible swap of texture points during */
/* the left shift process. This allows "dynamical" effects and for example "ghost" subsets */
/* subsets of the 3D object that appear and disappear according to the point of view. */
DepthChoice=1;
/* Definition : */
/* */
/* 0 : sinusoidal, */
/* 1 : gaussian. */
/* */
TextureChoice=1;
/* Definition : */
/* */
/* 0 : random, */
/* 1 : vertical lines, */
/* 2 : color bars. */
/* */
int X,Y;
for (Y=Ymin ; Y<=Ymax ; Y++)
{
for (X=Xmin ; X<=Xmax ; X++)
{
switch (TextureChoice)
{
case 0:
{
IMAGE(Texture,X,Y) = GreyLevel(drand48());
/* Computation of a random texture... */
break;
}
case 1:
{
IMAGE(Texture,X,Y) = GreyLevel(((X%(dimX/10))<=((dimX/100)-1)) ? 1 : 0);
/* Computation of vertical lines (introduced on 20110603132430). */
break;
}
case 2:
{
IMAGE(Texture,X,Y) = MODS((X*((dimX/100)-1)),BLACK,WHITE);
/* Computation of vertical color bars (introduced on 20110605093327). */
break;
}
default:
{
IMAGE(Texture,X,Y) = GreyLevel(0);
break;
}
}
switch (DepthChoice)
{
case 0:
{
IMAGE(Depth,X,Y) = GreyLevel((1+sin(4*3.1415*X_01(X)))/2);
/* Computation of a sinusoidal depth field. */
break;
}
case 1:
{
IMAGE(Depth,X,Y) = GreyLevel(exp(-10*(((X_01(X)-0.5)*(X_01(X)-0.5))+
((Y_01(Y)-0.5)*(Y_01(Y)-0.5))
)
)
);
/* Computation of a gaussian depth field (introduced on 20110603132430). */
break;
}
default:
{
IMAGE(Depth,X,Y) = GreyLevel(0);
break;
}
}
}
}
MultiplicativeFactor = 0.24;
IntrinsicPeriod = 0.2;
ActualPeriod = 0.2;
TextureSwap = 1;
AutostereogramGeneration(Autostereogram
,Depth,MultiplicativeFactor
,Texture,IntrinsicPeriod,ActualPeriod,TextureSwap
);
/* Computation of the random autostereogram. */
write(1,Autostereogram,dimX*dimY);
/* Acces to the generated autostereogram is given on 'Stdout'. */
}
return(0);
}