Page Menu
Home
c4science
Search
Configure Global Search
Log In
Files
F102271592
image.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Subscribers
None
File Metadata
Details
File Info
Storage
Attached
Created
Tue, Feb 18, 23:34
Size
54 KB
Mime Type
text/x-c
Expires
Thu, Feb 20, 23:34 (1 d, 23 h)
Engine
blob
Format
Raw Data
Handle
24321138
Attached To
rLAMMPS lammps
image.cpp
View Options
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
http://lammps.sandia.gov, Sandia National Laboratories
Steve Plimpton, sjplimp@sandia.gov
Copyright (2003) Sandia Corporation. Under the terms of Contract
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
certain rights in this software. This software is distributed under
the GNU General Public License.
See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */
/* ----------------------------------------------------------------------
Contributing author: Nathan Fabian (Sandia)
------------------------------------------------------------------------- */
#include "mpi.h"
#include "math.h"
#include "ctype.h"
#include "stdlib.h"
#include "string.h"
#include "image.h"
#include "math_extra.h"
#include "random_mars.h"
#include "math_const.h"
#include "error.h"
#include "memory.h"
#ifdef LAMMPS_JPEG
#include "jpeglib.h"
#endif
using
namespace
LAMMPS_NS
;
using
namespace
MathConst
;
#define NCOLORS 140
#define NELEMENTS 109
#define BIG 1.0e20
enum
{
NUMERIC
,
MINVALUE
,
MAXVALUE
};
enum
{
CONTINUOUS
,
DISCRETE
,
SEQUENTIAL
};
enum
{
ABSOLUTE
,
FRACTIONAL
};
enum
{
NO
,
YES
};
/* ---------------------------------------------------------------------- */
Image
::
Image
(
LAMMPS
*
lmp
)
:
Pointers
(
lmp
)
{
MPI_Comm_rank
(
world
,
&
me
);
MPI_Comm_size
(
world
,
&
nprocs
);
// defaults
width
=
height
=
512
;
theta
=
60.0
*
MY_PI
/
180.0
;
phi
=
30.0
*
MY_PI
/
180.0
;
zoom
=
1.0
;
persp
=
0.0
;
shiny
=
1.0
;
ssao
=
NO
;
// colors
ncolors
=
0
;
username
=
NULL
;
userrgb
=
NULL
;
boxcolor
=
color2rgb
(
"yellow"
);
background
[
0
]
=
background
[
1
]
=
background
[
2
]
=
0
;
// default color map
mlo
=
MINVALUE
;
mhi
=
MAXVALUE
;
mstyle
=
CONTINUOUS
;
mrange
=
FRACTIONAL
;
nentry
=
2
;
mentry
=
new
MapEntry
[
nentry
];
mentry
[
0
].
svalue
=
0.0
;
mentry
[
0
].
color
=
color2rgb
(
"blue"
);
mentry
[
1
].
svalue
=
1.0
;
mentry
[
1
].
color
=
color2rgb
(
"red"
);
// static parameters
FOV
=
MY_PI
/
6.0
;
// 30 degrees
ambientColor
[
0
]
=
0.0
;
ambientColor
[
1
]
=
0.0
;
ambientColor
[
2
]
=
0.0
;
keyLightPhi
=
-
MY_PI4
;
// -45 degrees
keyLightTheta
=
MY_PI
/
6.0
;
// 30 degrees
keyLightColor
[
0
]
=
0.9
;
keyLightColor
[
1
]
=
0.9
;
keyLightColor
[
2
]
=
0.9
;
fillLightPhi
=
MY_PI
/
6.0
;
// 30 degrees
fillLightTheta
=
0
;
fillLightColor
[
0
]
=
0.45
;
fillLightColor
[
1
]
=
0.45
;
fillLightColor
[
2
]
=
0.45
;
backLightPhi
=
MY_PI
;
// 180 degrees
backLightTheta
=
MY_PI
/
12.0
;
// 15 degrees
backLightColor
[
0
]
=
0.9
;
backLightColor
[
1
]
=
0.9
;
backLightColor
[
2
]
=
0.9
;
// RNG for SSAO depth shading
if
(
ssao
)
random
=
new
RanMars
(
lmp
,
seed
+
me
);
else
random
=
NULL
;
}
/* ---------------------------------------------------------------------- */
Image
::~
Image
()
{
for
(
int
i
=
0
;
i
<
ncolors
;
i
++
)
delete
[]
username
[
i
];
memory
->
sfree
(
username
);
memory
->
destroy
(
userrgb
);
delete
[]
mentry
;
memory
->
destroy
(
depthBuffer
);
memory
->
destroy
(
surfaceBuffer
);
memory
->
destroy
(
imageBuffer
);
memory
->
destroy
(
depthcopy
);
memory
->
destroy
(
surfacecopy
);
memory
->
destroy
(
rgbcopy
);
delete
random
;
}
/* ----------------------------------------------------------------------
allocate image and depth buffers
called after image size is set
------------------------------------------------------------------------- */
void
Image
::
buffers
()
{
npixels
=
width
*
height
;
memory
->
create
(
depthBuffer
,
npixels
,
"image:depthBuffer"
);
memory
->
create
(
surfaceBuffer
,
2
*
npixels
,
"image:surfaceBuffer"
);
memory
->
create
(
imageBuffer
,
3
*
npixels
,
"image:imageBuffer"
);
memory
->
create
(
depthcopy
,
npixels
,
"image:depthcopy"
);
memory
->
create
(
surfacecopy
,
2
*
npixels
,
"image:surfacecopy"
);
memory
->
create
(
rgbcopy
,
3
*
npixels
,
"image:rgbcopy"
);
}
/* ----------------------------------------------------------------------
reset view parameters
called once if view is STATIC
called before every render if view is DYNAMIC
------------------------------------------------------------------------- */
void
Image
::
view_params
(
double
boxxlo
,
double
boxxhi
,
double
boxylo
,
double
boxyhi
,
double
boxzlo
,
double
boxzhi
)
{
// camDir points at the camera, view direction = -camDir
camDir
[
0
]
=
sin
(
theta
)
*
cos
(
phi
);
camDir
[
1
]
=
sin
(
theta
)
*
sin
(
phi
);
camDir
[
2
]
=
cos
(
theta
);
// zdist = camera distance = function of zoom & bounding box
// camPos = camera position = function of camDir and zdist
double
delx
=
2.0
*
(
boxxhi
-
boxxlo
);
double
dely
=
2.0
*
(
boxyhi
-
boxylo
);
double
delz
=
2.0
*
(
boxzhi
-
boxzlo
);
double
maxdel
=
MAX
(
delx
,
dely
);
maxdel
=
MAX
(
maxdel
,
delz
);
zdist
=
maxdel
;
zdist
/=
tan
(
FOV
);
zdist
+=
0.5
*
(
delx
*
camDir
[
0
]
+
dely
*
camDir
[
1
]
+
delz
*
camDir
[
2
]);
zdist
/=
zoom
;
camPos
[
0
]
=
camDir
[
0
]
*
zdist
;
camPos
[
1
]
=
camDir
[
1
]
*
zdist
;
camPos
[
2
]
=
camDir
[
2
]
*
zdist
;
// normalize up vector
if
(
up
[
0
]
==
0.0
&&
up
[
1
]
==
0.0
&&
up
[
2
]
==
0.0
)
error
->
all
(
FLERR
,
"Invalid image up vector"
);
MathExtra
::
norm3
(
up
);
// rotate up if camDir and up point in same direction
// should also check for opposite direction
// NOTE: this is not yet right for preserving view as rotate thru up
if
(
camDir
[
0
]
==
up
[
0
]
&&
camDir
[
1
]
==
up
[
1
]
&&
camDir
[
2
]
==
up
[
2
])
{
double
tmp
=
up
[
0
];
up
[
0
]
=
up
[
1
];
up
[
1
]
=
up
[
2
];
up
[
2
]
=
tmp
;
}
// camUp = camDir x (Up x camDir)
MathExtra
::
cross3
(
up
,
camDir
,
camRight
);
MathExtra
::
norm3
(
camRight
);
MathExtra
::
cross3
(
camDir
,
camRight
,
camUp
);
if
(
camUp
[
0
]
==
0.0
&&
camUp
[
1
]
==
0.0
&&
camUp
[
2
]
==
0.0
)
error
->
all
(
FLERR
,
"Invalid image up vector"
);
MathExtra
::
norm3
(
camUp
);
// light directions in terms of -camDir = z
keyLightDir
[
0
]
=
cos
(
keyLightTheta
)
*
sin
(
keyLightPhi
);
keyLightDir
[
1
]
=
sin
(
keyLightTheta
);
keyLightDir
[
2
]
=
cos
(
keyLightTheta
)
*
cos
(
keyLightPhi
);
fillLightDir
[
0
]
=
cos
(
fillLightTheta
)
*
sin
(
fillLightPhi
);
fillLightDir
[
1
]
=
sin
(
fillLightTheta
);
fillLightDir
[
2
]
=
cos
(
fillLightTheta
)
*
cos
(
fillLightPhi
);
backLightDir
[
0
]
=
cos
(
backLightTheta
)
*
sin
(
backLightPhi
);
backLightDir
[
1
]
=
sin
(
backLightTheta
);
backLightDir
[
2
]
=
cos
(
backLightTheta
)
*
cos
(
backLightPhi
);
keyHalfDir
[
0
]
=
0
+
keyLightDir
[
0
];
keyHalfDir
[
1
]
=
0
+
keyLightDir
[
1
];
keyHalfDir
[
2
]
=
1
+
keyLightDir
[
2
];
MathExtra
::
norm3
(
keyHalfDir
);
// adjust shinyness of the reflection
specularHardness
=
16.0
*
shiny
;
specularIntensity
=
shiny
;
// adjust strength of the SSAO
if
(
ssao
)
{
SSAORadius
=
maxdel
*
0.05
*
ssaoint
;
SSAOSamples
=
static_cast
<
int
>
(
8.0
+
32.0
*
ssaoint
);
SSAOJitter
=
MY_PI
/
12
;
ambientColor
[
0
]
=
0.5
;
ambientColor
[
1
]
=
0.5
;
ambientColor
[
2
]
=
0.5
;
}
// param for rasterizing spheres
tanPerPixel
=
-
(
maxdel
/
(
double
)
height
);
}
/* ----------------------------------------------------------------------
set explicit values for all min/max settings in color map
lo/hi current and lvalue/hvalue settings for lo/hi = MIN/MAX VALUE in entries
if mlo/mhi = MIN/MAX VALUE, compute bounds on just the atoms being visualized
------------------------------------------------------------------------- */
void
Image
::
color_minmax
(
int
n
,
double
*
buf
,
int
stride
)
{
double
two
[
2
],
twoall
[
2
];
if
(
mlo
==
MINVALUE
||
mhi
==
MAXVALUE
)
{
double
lo
=
BIG
;
double
hi
=
-
BIG
;
int
m
=
0
;
for
(
int
i
=
0
;
i
<
n
;
i
++
)
{
lo
=
MIN
(
lo
,
buf
[
m
]);
hi
=
MAX
(
hi
,
buf
[
m
]);
m
+=
stride
;
}
two
[
0
]
=
-
lo
;
two
[
1
]
=
hi
;
MPI_Allreduce
(
two
,
twoall
,
2
,
MPI_DOUBLE
,
MPI_MAX
,
world
);
}
if
(
mlo
==
MINVALUE
)
locurrent
=
-
twoall
[
0
];
else
locurrent
=
mlovalue
;
if
(
mhi
==
MAXVALUE
)
hicurrent
=
twoall
[
1
];
else
hicurrent
=
mhivalue
;
if
(
locurrent
>
hicurrent
)
error
->
all
(
FLERR
,
"Invalid image color range"
);
if
(
mstyle
==
CONTINUOUS
)
{
if
(
mrange
==
ABSOLUTE
)
mentry
[
0
].
svalue
=
locurrent
;
else
mentry
[
0
].
svalue
=
0.0
;
if
(
mrange
==
ABSOLUTE
)
mentry
[
nentry
-
1
].
svalue
=
hicurrent
;
else
mentry
[
nentry
-
1
].
svalue
=
1.0
;
}
else
if
(
mstyle
==
DISCRETE
)
{
for
(
int
i
=
0
;
i
<
nentry
;
i
++
)
{
if
(
mentry
[
i
].
lo
==
MINVALUE
)
{
if
(
mrange
==
ABSOLUTE
)
mentry
[
i
].
lvalue
=
locurrent
;
else
mentry
[
i
].
lvalue
=
0.0
;
}
if
(
mentry
[
i
].
hi
==
MAXVALUE
)
{
if
(
mrange
==
ABSOLUTE
)
mentry
[
i
].
hvalue
=
hicurrent
;
else
mentry
[
i
].
hvalue
=
1.0
;
}
}
}
}
/* ----------------------------------------------------------------------
initialize image to background color and depth buffer
no need to init surfaceBuffer, since will be based on depth
------------------------------------------------------------------------- */
void
Image
::
clear
()
{
int
red
=
background
[
0
];
int
green
=
background
[
1
];
int
blue
=
background
[
2
];
int
ix
,
iy
;
for
(
iy
=
0
;
iy
<
height
;
iy
++
)
for
(
ix
=
0
;
ix
<
width
;
ix
++
)
{
imageBuffer
[
iy
*
width
*
3
+
ix
*
3
+
0
]
=
red
;
imageBuffer
[
iy
*
width
*
3
+
ix
*
3
+
1
]
=
green
;
imageBuffer
[
iy
*
width
*
3
+
ix
*
3
+
2
]
=
blue
;
depthBuffer
[
iy
*
width
+
ix
]
=
-
1
;
}
}
/* ----------------------------------------------------------------------
merge image from each processor into one composite image
done pixel by pixel, respecting depth buffer
hi procs send to lo procs, cascading down logarithmically
------------------------------------------------------------------------- */
void
Image
::
merge
()
{
MPI_Request
requests
[
3
];
MPI_Status
statuses
[
3
];
int
nhalf
=
1
;
while
(
nhalf
<
nprocs
)
nhalf
*=
2
;
nhalf
/=
2
;
while
(
nhalf
)
{
if
(
me
<
nhalf
&&
me
+
nhalf
<
nprocs
)
{
MPI_Irecv
(
rgbcopy
,
npixels
*
3
,
MPI_BYTE
,
me
+
nhalf
,
0
,
world
,
&
requests
[
0
]);
MPI_Irecv
(
depthcopy
,
npixels
,
MPI_DOUBLE
,
me
+
nhalf
,
0
,
world
,
&
requests
[
1
]);
if
(
ssao
)
MPI_Irecv
(
surfacecopy
,
npixels
*
2
,
MPI_DOUBLE
,
me
+
nhalf
,
0
,
world
,
&
requests
[
2
]);
if
(
ssao
)
MPI_Waitall
(
3
,
requests
,
statuses
);
else
MPI_Waitall
(
2
,
requests
,
statuses
);
for
(
int
i
=
0
;
i
<
npixels
;
i
++
)
{
if
(
depthBuffer
[
i
]
<
0
||
(
depthcopy
[
i
]
>=
0
&&
depthcopy
[
i
]
<
depthBuffer
[
i
]))
{
depthBuffer
[
i
]
=
depthcopy
[
i
];
imageBuffer
[
i
*
3
+
0
]
=
rgbcopy
[
i
*
3
+
0
];
imageBuffer
[
i
*
3
+
1
]
=
rgbcopy
[
i
*
3
+
1
];
imageBuffer
[
i
*
3
+
2
]
=
rgbcopy
[
i
*
3
+
2
];
if
(
ssao
)
{
surfaceBuffer
[
i
*
2
+
0
]
=
surfacecopy
[
i
*
2
+
0
];
surfaceBuffer
[
i
*
2
+
1
]
=
surfacecopy
[
i
*
2
+
1
];
}
}
}
}
else
if
(
me
>=
nhalf
&&
me
<
2
*
nhalf
)
{
MPI_Send
(
imageBuffer
,
npixels
*
3
,
MPI_BYTE
,
me
-
nhalf
,
0
,
world
);
MPI_Send
(
depthBuffer
,
npixels
,
MPI_DOUBLE
,
me
-
nhalf
,
0
,
world
);
if
(
ssao
)
MPI_Send
(
surfaceBuffer
,
npixels
*
2
,
MPI_DOUBLE
,
me
-
nhalf
,
0
,
world
);
}
nhalf
/=
2
;
}
// extra SSAO enhancement
// bcast full image to all procs
// each works on subset of pixels
// gather result back to proc 0
if
(
ssao
)
{
MPI_Bcast
(
imageBuffer
,
npixels
*
3
,
MPI_BYTE
,
0
,
world
);
MPI_Bcast
(
surfaceBuffer
,
npixels
*
2
,
MPI_DOUBLE
,
0
,
world
);
MPI_Bcast
(
depthBuffer
,
npixels
,
MPI_DOUBLE
,
0
,
world
);
compute_SSAO
();
int
pixelPart
=
height
/
nprocs
*
width
*
3
;
MPI_Gather
(
imageBuffer
+
me
*
pixelPart
,
pixelPart
,
MPI_BYTE
,
rgbcopy
,
pixelPart
,
MPI_BYTE
,
0
,
world
);
writeBuffer
=
rgbcopy
;
}
else
{
writeBuffer
=
imageBuffer
;
}
}
/* ----------------------------------------------------------------------
draw simulation bounding box as 12 cylinders
------------------------------------------------------------------------- */
void
Image
::
draw_box
(
double
(
*
corners
)[
3
],
double
diameter
)
{
draw_cylinder
(
corners
[
0
],
corners
[
1
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
2
],
corners
[
3
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
0
],
corners
[
2
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
1
],
corners
[
3
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
0
],
corners
[
4
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
1
],
corners
[
5
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
2
],
corners
[
6
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
3
],
corners
[
7
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
4
],
corners
[
5
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
6
],
corners
[
7
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
4
],
corners
[
6
],
boxcolor
,
diameter
,
3
);
draw_cylinder
(
corners
[
5
],
corners
[
7
],
boxcolor
,
diameter
,
3
);
}
/* ----------------------------------------------------------------------
draw XYZ axes in red/green/blue
axes = 4 end points
------------------------------------------------------------------------- */
void
Image
::
draw_axes
(
double
(
*
axes
)[
3
],
double
diameter
)
{
draw_cylinder
(
axes
[
0
],
axes
[
1
],
color2rgb
(
"red"
),
diameter
,
3
);
draw_cylinder
(
axes
[
0
],
axes
[
2
],
color2rgb
(
"green"
),
diameter
,
3
);
draw_cylinder
(
axes
[
0
],
axes
[
3
],
color2rgb
(
"blue"
),
diameter
,
3
);
}
/* ----------------------------------------------------------------------
draw sphere at x with surfaceColor and diameter
render pixel by pixel onto image plane with depth buffering
------------------------------------------------------------------------- */
void
Image
::
draw_sphere
(
double
*
x
,
double
*
surfaceColor
,
double
diameter
)
{
int
ix
,
iy
;
double
projRad
;
double
xlocal
[
3
],
surface
[
3
];
double
depth
;
xlocal
[
0
]
=
x
[
0
]
-
xctr
;
xlocal
[
1
]
=
x
[
1
]
-
yctr
;
xlocal
[
2
]
=
x
[
2
]
-
zctr
;
double
xmap
=
MathExtra
::
dot3
(
camRight
,
xlocal
);
double
ymap
=
MathExtra
::
dot3
(
camUp
,
xlocal
);
double
dist
=
MathExtra
::
dot3
(
camPos
,
camDir
)
-
MathExtra
::
dot3
(
xlocal
,
camDir
);
double
radius
=
0.5
*
diameter
;
double
radsq
=
radius
*
radius
;
double
pixelWidth
=
(
tanPerPixel
>
0
)
?
tanPerPixel
*
dist
:
-
tanPerPixel
/
zoom
;
double
pixelRadiusFull
=
radius
/
pixelWidth
;
int
pixelRadius
=
static_cast
<
int
>
(
pixelRadiusFull
+
0.5
)
+
1
;
double
xf
=
xmap
/
pixelWidth
;
double
yf
=
ymap
/
pixelWidth
;
int
xc
=
static_cast
<
int
>
(
xf
);
int
yc
=
static_cast
<
int
>
(
yf
);
double
width_error
=
xf
-
xc
;
double
height_error
=
yf
-
yc
;
// shift 0,0 to screen center (vs lower left)
xc
+=
width
/
2
;
yc
+=
height
/
2
;
for
(
iy
=
yc
-
pixelRadius
;
iy
<=
yc
+
pixelRadius
;
iy
++
)
{
for
(
ix
=
xc
-
pixelRadius
;
ix
<=
xc
+
pixelRadius
;
ix
++
)
{
if
(
iy
<
0
||
iy
>=
height
||
ix
<
0
||
ix
>=
width
)
continue
;
surface
[
1
]
=
((
iy
-
yc
)
-
height_error
)
*
pixelWidth
;
surface
[
0
]
=
((
ix
-
xc
)
-
width_error
)
*
pixelWidth
;
projRad
=
surface
[
0
]
*
surface
[
0
]
+
surface
[
1
]
*
surface
[
1
];
// outside the sphere in the projected image
if
(
projRad
>
radsq
)
continue
;
surface
[
2
]
=
sqrt
(
radsq
-
projRad
);
depth
=
dist
-
surface
[
2
];
surface
[
0
]
/=
radius
;
surface
[
1
]
/=
radius
;
surface
[
2
]
/=
radius
;
draw_pixel
(
ix
,
iy
,
depth
,
surface
,
surfaceColor
);
}
}
}
/* ----------------------------------------------------------------------
draw axis oriented cube at x with surfaceColor and diameter in size
render pixel by pixel onto image plane with depth buffering
------------------------------------------------------------------------- */
void
Image
::
draw_cube
(
double
*
x
,
double
*
surfaceColor
,
double
diameter
)
{
double
xlocal
[
3
],
surface
[
3
],
normal
[
3
];
double
t
,
tdir
[
3
];
double
depth
;
xlocal
[
0
]
=
x
[
0
]
-
xctr
;
xlocal
[
1
]
=
x
[
1
]
-
yctr
;
xlocal
[
2
]
=
x
[
2
]
-
zctr
;
double
xmap
=
MathExtra
::
dot3
(
camRight
,
xlocal
);
double
ymap
=
MathExtra
::
dot3
(
camUp
,
xlocal
);
double
dist
=
MathExtra
::
dot3
(
camPos
,
camDir
)
-
MathExtra
::
dot3
(
xlocal
,
camDir
);
double
radius
=
0.5
*
diameter
;
double
pixelWidth
=
(
tanPerPixel
>
0
)
?
tanPerPixel
*
dist
:
-
tanPerPixel
/
zoom
;
double
halfWidth
=
diameter
;
double
pixelHalfWidthFull
=
halfWidth
/
pixelWidth
;
int
pixelHalfWidth
=
static_cast
<
int
>
(
pixelHalfWidthFull
+
0.5
);
double
xf
=
xmap
/
pixelWidth
;
double
yf
=
ymap
/
pixelWidth
;
int
xc
=
static_cast
<
int
>
(
xf
);
int
yc
=
static_cast
<
int
>
(
yf
);
double
width_error
=
xf
-
xc
;
double
height_error
=
yf
-
yc
;
// shift 0,0 to screen center (vs lower left)
xc
+=
width
/
2
;
yc
+=
height
/
2
;
for
(
int
iy
=
yc
-
pixelHalfWidth
;
iy
<=
yc
+
pixelHalfWidth
;
iy
++
)
{
for
(
int
ix
=
xc
-
pixelHalfWidth
;
ix
<=
xc
+
pixelHalfWidth
;
ix
++
)
{
if
(
iy
<
0
||
iy
>=
height
||
ix
<
0
||
ix
>=
width
)
continue
;
double
sy
=
((
iy
-
yc
)
-
height_error
)
*
pixelWidth
;
double
sx
=
((
ix
-
xc
)
-
width_error
)
*
pixelWidth
;
surface
[
0
]
=
camRight
[
0
]
*
sx
+
camUp
[
0
]
*
sy
;
surface
[
1
]
=
camRight
[
1
]
*
sx
+
camUp
[
1
]
*
sy
;
surface
[
2
]
=
camRight
[
2
]
*
sx
+
camUp
[
2
]
*
sy
;
// iterate through each of the 6 axis-oriented planes of the box
// only render up to 3 which are facing the camera
// these checks short circuit a dot product, testing for > 0
for
(
int
dim
=
0
;
dim
<
3
;
dim
++
)
{
if
(
camDir
[
dim
]
>
0
)
{
// positive faces camera
t
=
(
radius
-
surface
[
dim
])
/
camDir
[
dim
];
normal
[
0
]
=
camRight
[
dim
];
normal
[
1
]
=
camUp
[
dim
];
normal
[
2
]
=
camDir
[
dim
];
}
else
if
(
camDir
[
dim
]
<
0
)
{
// negative faces camera
t
=
-
(
radius
+
surface
[
dim
])
/
camDir
[
dim
];
normal
[
0
]
=
-
camRight
[
dim
];
normal
[
1
]
=
-
camUp
[
dim
];
normal
[
2
]
=
-
camDir
[
dim
];
}
if
(
camDir
[
dim
]
!=
0
)
{
tdir
[
0
]
=
camDir
[
0
]
*
t
;
tdir
[
1
]
=
camDir
[
1
]
*
t
;
tdir
[
2
]
=
camDir
[
2
]
*
t
;
bool
xin
=
((
surface
[
0
]
+
tdir
[
0
])
>=
-
radius
)
&&
((
surface
[
0
]
+
tdir
[
0
])
<=
radius
);
bool
yin
=
((
surface
[
1
]
+
tdir
[
1
])
>=
-
radius
)
&&
((
surface
[
1
]
+
tdir
[
1
])
<=
radius
);
bool
zin
=
((
surface
[
2
]
+
tdir
[
2
])
>=
-
radius
)
&&
((
surface
[
2
]
+
tdir
[
2
])
<=
radius
);
switch
(
dim
)
{
case
0
:
if
(
yin
&
zin
)
{
depth
=
dist
-
t
;
draw_pixel
(
ix
,
iy
,
depth
,
normal
,
surfaceColor
);
}
break
;
case
1
:
if
(
xin
&
zin
)
{
depth
=
dist
-
t
;
draw_pixel
(
ix
,
iy
,
depth
,
normal
,
surfaceColor
);
}
break
;
case
2
:
if
(
xin
&
yin
)
{
depth
=
dist
-
t
;
draw_pixel
(
ix
,
iy
,
depth
,
normal
,
surfaceColor
);
}
break
;
}
}
}
}
}
}
/* ----------------------------------------------------------------------
draw cylinder from x to y with surfaceColor and diameter
render pixel by pixel onto image plane with depth buffering
if sflag = 0, draw no end spheres
if sflag = 1, draw 1st end sphere
if sflag = 2, draw 2nd end sphere
if sflag = 3, draw both end spheres
------------------------------------------------------------------------- */
void
Image
::
draw_cylinder
(
double
*
x
,
double
*
y
,
double
*
surfaceColor
,
double
diameter
,
int
sflag
)
{
double
surface
[
3
],
normal
[
3
];
double
mid
[
3
],
xaxis
[
3
],
yaxis
[
3
],
zaxis
[
3
];
double
camLDir
[
3
],
camLRight
[
3
],
camLUp
[
3
];
double
zmin
,
zmax
;
if
(
sflag
%
2
)
draw_sphere
(
x
,
surfaceColor
,
diameter
);
if
(
sflag
/
2
)
draw_sphere
(
y
,
surfaceColor
,
diameter
);
double
radius
=
0.5
*
diameter
;
double
radsq
=
radius
*
radius
;
zaxis
[
0
]
=
y
[
0
]
-
x
[
0
];
zaxis
[
1
]
=
y
[
1
]
-
x
[
1
];
zaxis
[
2
]
=
y
[
2
]
-
x
[
2
];
double
rasterWidth
=
fabs
(
MathExtra
::
dot3
(
zaxis
,
camRight
))
+
diameter
;
double
rasterHeight
=
fabs
(
MathExtra
::
dot3
(
zaxis
,
camUp
))
+
diameter
;
mid
[
0
]
=
(
y
[
0
]
+
x
[
0
])
*
0.5
-
xctr
;
mid
[
1
]
=
(
y
[
1
]
+
x
[
1
])
*
0.5
-
yctr
;
mid
[
2
]
=
(
y
[
2
]
+
x
[
2
])
*
0.5
-
zctr
;
double
len
=
MathExtra
::
len3
(
zaxis
);
MathExtra
::
scale3
(
1.0
/
len
,
zaxis
);
len
*=
0.5
;
zmax
=
len
;
zmin
=
-
len
;
double
xmap
=
MathExtra
::
dot3
(
camRight
,
mid
);
double
ymap
=
MathExtra
::
dot3
(
camUp
,
mid
);
double
dist
=
MathExtra
::
dot3
(
camPos
,
camDir
)
-
MathExtra
::
dot3
(
mid
,
camDir
);
double
pixelWidth
=
(
tanPerPixel
>
0
)
?
tanPerPixel
*
dist
:
-
tanPerPixel
/
zoom
;
double
xf
=
xmap
/
pixelWidth
;
double
yf
=
ymap
/
pixelWidth
;
int
xc
=
static_cast
<
int
>
(
xf
);
int
yc
=
static_cast
<
int
>
(
yf
);
double
width_error
=
xf
-
xc
;
double
height_error
=
yf
-
yc
;
// shift 0,0 to screen center (vs lower left)
xc
+=
width
/
2
;
yc
+=
height
/
2
;
double
pixelHalfWidthFull
=
(
rasterWidth
*
0.5
)
/
pixelWidth
;
double
pixelHalfHeightFull
=
(
rasterHeight
*
0.5
)
/
pixelWidth
;
int
pixelHalfWidth
=
static_cast
<
int
>
(
pixelHalfWidthFull
+
0.5
);
int
pixelHalfHeight
=
static_cast
<
int
>
(
pixelHalfHeightFull
+
0.5
);
if
(
zaxis
[
0
]
==
camDir
[
0
]
&&
zaxis
[
1
]
==
camDir
[
1
]
&&
zaxis
[
2
]
==
camDir
[
2
])
return
;
if
(
zaxis
[
0
]
==
-
camDir
[
0
]
&&
zaxis
[
1
]
==
-
camDir
[
1
]
&&
zaxis
[
2
]
==
-
camDir
[
2
])
return
;
MathExtra
::
cross3
(
zaxis
,
camDir
,
yaxis
);
MathExtra
::
norm3
(
yaxis
);
MathExtra
::
cross3
(
yaxis
,
zaxis
,
xaxis
);
MathExtra
::
norm3
(
xaxis
);
camLDir
[
0
]
=
MathExtra
::
dot3
(
camDir
,
xaxis
);
camLDir
[
1
]
=
0.0
;
camLDir
[
2
]
=
MathExtra
::
dot3
(
camDir
,
zaxis
);
camLRight
[
0
]
=
MathExtra
::
dot3
(
camRight
,
xaxis
);
camLRight
[
1
]
=
MathExtra
::
dot3
(
camRight
,
yaxis
);
camLRight
[
2
]
=
MathExtra
::
dot3
(
camRight
,
zaxis
);
MathExtra
::
norm3
(
camLRight
);
camLUp
[
0
]
=
MathExtra
::
dot3
(
camUp
,
xaxis
);
camLUp
[
1
]
=
MathExtra
::
dot3
(
camUp
,
yaxis
);
camLUp
[
2
]
=
MathExtra
::
dot3
(
camUp
,
zaxis
);
MathExtra
::
norm3
(
camLUp
);
double
a
=
camLDir
[
0
]
*
camLDir
[
0
];
for
(
int
iy
=
yc
-
pixelHalfHeight
;
iy
<=
yc
+
pixelHalfHeight
;
iy
++
)
{
for
(
int
ix
=
xc
-
pixelHalfWidth
;
ix
<=
xc
+
pixelHalfWidth
;
ix
++
)
{
if
(
iy
<
0
||
iy
>=
height
||
ix
<
0
||
ix
>=
width
)
continue
;
double
sy
=
((
iy
-
yc
)
-
height_error
)
*
pixelWidth
;
double
sx
=
((
ix
-
xc
)
-
width_error
)
*
pixelWidth
;
surface
[
0
]
=
camLRight
[
0
]
*
sx
+
camLUp
[
0
]
*
sy
;
surface
[
1
]
=
camLRight
[
1
]
*
sx
+
camLUp
[
1
]
*
sy
;
surface
[
2
]
=
camLRight
[
2
]
*
sx
+
camLUp
[
2
]
*
sy
;
double
b
=
2
*
camLDir
[
0
]
*
surface
[
0
];
double
c
=
surface
[
0
]
*
surface
[
0
]
+
surface
[
1
]
*
surface
[
1
]
-
radsq
;
double
partial
=
b
*
b
-
4
*
a
*
c
;
if
(
partial
<
0
)
continue
;
partial
=
sqrt
(
partial
);
double
t
=
(
-
b
+
partial
)
/
(
2
*
a
);
double
t2
=
(
-
b
-
partial
)
/
(
2
*
a
);
if
(
t2
>
t
)
{
t
=
t2
;
}
surface
[
0
]
+=
t
*
camLDir
[
0
];
surface
[
1
]
+=
t
*
camLDir
[
1
];
surface
[
2
]
+=
t
*
camLDir
[
2
];
if
(
surface
[
2
]
>
zmax
||
surface
[
2
]
<
zmin
)
continue
;
// convert surface into the surface normal
normal
[
0
]
=
surface
[
0
]
/
radius
;
normal
[
1
]
=
surface
[
1
]
/
radius
;
normal
[
2
]
=
0.0
;
// in camera space
surface
[
0
]
=
MathExtra
::
dot3
(
normal
,
camLRight
);
surface
[
1
]
=
MathExtra
::
dot3
(
normal
,
camLUp
);
surface
[
2
]
=
MathExtra
::
dot3
(
normal
,
camLDir
);
double
depth
=
dist
-
t
;
draw_pixel
(
ix
,
iy
,
depth
,
surface
,
surfaceColor
);
}
}
}
/* ----------------------------------------------------------------------
draw triangle with 3 corner points x,y,z and surfaceColor
------------------------------------------------------------------------- */
void
Image
::
draw_triangle
(
double
*
x
,
double
*
y
,
double
*
z
,
double
*
surfaceColor
)
{
double
d1
[
3
],
d1len
,
d2
[
3
],
d2len
,
normal
[
3
],
invndotd
;
double
xlocal
[
3
],
ylocal
[
3
],
zlocal
[
3
];
double
center
[
3
],
bounds
[
6
];
double
surface
[
3
];
double
depth
;
xlocal
[
0
]
=
x
[
0
]
-
xctr
;
xlocal
[
1
]
=
x
[
1
]
-
yctr
;
xlocal
[
2
]
=
x
[
2
]
-
zctr
;
ylocal
[
0
]
=
y
[
0
]
-
xctr
;
ylocal
[
1
]
=
y
[
1
]
-
yctr
;
ylocal
[
2
]
=
y
[
2
]
-
zctr
;
zlocal
[
0
]
=
z
[
0
]
-
xctr
;
zlocal
[
1
]
=
z
[
1
]
-
yctr
;
zlocal
[
2
]
=
z
[
2
]
-
zctr
;
MathExtra
::
sub3
(
xlocal
,
ylocal
,
d1
);
d1len
=
MathExtra
::
len3
(
d1
);
MathExtra
::
scale3
(
1.0
/
d1len
,
d1
);
MathExtra
::
sub3
(
zlocal
,
ylocal
,
d2
);
d2len
=
MathExtra
::
len3
(
d2
);
MathExtra
::
scale3
(
1.0
/
d2len
,
d2
);
MathExtra
::
cross3
(
d1
,
d2
,
normal
);
MathExtra
::
norm3
(
normal
);
invndotd
=
1.0
/
MathExtra
::
dot3
(
normal
,
camDir
);
// invalid triangle (parallel)
if
(
invndotd
==
0
)
return
;
double
r
[
3
],
u
[
3
];
center
[
0
]
=
(
xlocal
[
0
]
+
ylocal
[
0
]
+
zlocal
[
0
])
/
3
;
center
[
1
]
=
(
xlocal
[
1
]
+
ylocal
[
1
]
+
zlocal
[
1
])
/
3
;
center
[
2
]
=
(
xlocal
[
2
]
+
ylocal
[
2
]
+
zlocal
[
2
])
/
3
;
r
[
0
]
=
MathExtra
::
dot3
(
camRight
,
xlocal
);
r
[
1
]
=
MathExtra
::
dot3
(
camRight
,
ylocal
);
r
[
2
]
=
MathExtra
::
dot3
(
camRight
,
zlocal
);
u
[
0
]
=
MathExtra
::
dot3
(
camUp
,
xlocal
);
u
[
1
]
=
MathExtra
::
dot3
(
camUp
,
ylocal
);
u
[
2
]
=
MathExtra
::
dot3
(
camUp
,
zlocal
);
double
rasterLeft
=
r
[
0
]
-
MIN
(
r
[
0
],
MIN
(
r
[
1
],
r
[
2
]));
double
rasterRight
=
MAX
(
r
[
0
],
MAX
(
r
[
1
],
r
[
2
]))
-
r
[
0
];
double
rasterDown
=
u
[
0
]
-
MIN
(
u
[
0
],
MIN
(
u
[
1
],
u
[
2
]));
double
rasterUp
=
MAX
(
u
[
0
],
MAX
(
u
[
1
],
u
[
2
]))
-
u
[
0
];
double
xmap
=
MathExtra
::
dot3
(
camRight
,
xlocal
);
double
ymap
=
MathExtra
::
dot3
(
camUp
,
xlocal
);
double
dist
=
MathExtra
::
dot3
(
camPos
,
camDir
)
-
MathExtra
::
dot3
(
xlocal
,
camDir
);
double
pixelWidth
=
(
tanPerPixel
>
0
)
?
tanPerPixel
*
dist
:
-
tanPerPixel
/
zoom
;
double
xf
=
xmap
/
pixelWidth
;
double
yf
=
ymap
/
pixelWidth
;
int
xc
=
static_cast
<
int
>
(
xf
);
int
yc
=
static_cast
<
int
>
(
yf
);
double
width_error
=
xf
-
xc
;
double
height_error
=
yf
-
yc
;
// shift 0,0 to screen center (vs lower left)
xc
+=
width
/
2
;
yc
+=
height
/
2
;
double
pixelLeftFull
=
rasterLeft
/
pixelWidth
;
double
pixelRightFull
=
rasterRight
/
pixelWidth
;
double
pixelDownFull
=
rasterDown
/
pixelWidth
;
double
pixelUpFull
=
rasterUp
/
pixelWidth
;
int
pixelLeft
=
static_cast
<
int
>
(
pixelLeftFull
+
0.5
);
int
pixelRight
=
static_cast
<
int
>
(
pixelRightFull
+
0.5
);
int
pixelDown
=
static_cast
<
int
>
(
pixelDownFull
+
0.5
);
int
pixelUp
=
static_cast
<
int
>
(
pixelUpFull
+
0.5
);
for
(
int
iy
=
yc
-
pixelDown
;
iy
<=
yc
+
pixelUp
;
iy
++
)
{
for
(
int
ix
=
xc
-
pixelLeft
;
ix
<=
xc
+
pixelRight
;
ix
++
)
{
if
(
iy
<
0
||
iy
>=
height
||
ix
<
0
||
ix
>=
width
)
continue
;
double
sy
=
((
iy
-
yc
)
-
height_error
)
*
pixelWidth
;
double
sx
=
((
ix
-
xc
)
-
width_error
)
*
pixelWidth
;
surface
[
0
]
=
camRight
[
0
]
*
sx
+
camUp
[
0
]
*
sy
;
surface
[
1
]
=
camRight
[
1
]
*
sx
+
camUp
[
1
]
*
sy
;
surface
[
2
]
=
camRight
[
2
]
*
sx
+
camUp
[
2
]
*
sy
;
double
t
=
-
MathExtra
::
dot3
(
normal
,
surface
)
*
invndotd
;
// test inside the triangle
double
p
[
3
];
p
[
0
]
=
xlocal
[
0
]
+
surface
[
0
]
+
camDir
[
0
]
*
t
;
p
[
1
]
=
xlocal
[
1
]
+
surface
[
1
]
+
camDir
[
1
]
*
t
;
p
[
2
]
=
xlocal
[
2
]
+
surface
[
2
]
+
camDir
[
2
]
*
t
;
double
s1
[
3
],
s2
[
3
],
s3
[
3
];
double
c1
[
3
],
c2
[
3
];
MathExtra
::
sub3
(
zlocal
,
xlocal
,
s1
);
MathExtra
::
sub3
(
ylocal
,
xlocal
,
s2
);
MathExtra
::
sub3
(
p
,
xlocal
,
s3
);
MathExtra
::
cross3
(
s1
,
s2
,
c1
);
MathExtra
::
cross3
(
s1
,
s3
,
c2
);
if
(
MathExtra
::
dot3
(
c1
,
c2
)
<=
0
)
continue
;
MathExtra
::
sub3
(
xlocal
,
ylocal
,
s1
);
MathExtra
::
sub3
(
zlocal
,
ylocal
,
s2
);
MathExtra
::
sub3
(
p
,
ylocal
,
s3
);
MathExtra
::
cross3
(
s1
,
s2
,
c1
);
MathExtra
::
cross3
(
s1
,
s3
,
c2
);
if
(
MathExtra
::
dot3
(
c1
,
c2
)
<=
0
)
continue
;
MathExtra
::
sub3
(
ylocal
,
zlocal
,
s1
);
MathExtra
::
sub3
(
xlocal
,
zlocal
,
s2
);
MathExtra
::
sub3
(
p
,
zlocal
,
s3
);
MathExtra
::
cross3
(
s1
,
s2
,
c1
);
MathExtra
::
cross3
(
s1
,
s3
,
c2
);
if
(
MathExtra
::
dot3
(
c1
,
c2
)
<=
0
)
continue
;
double
cNormal
[
3
];
cNormal
[
0
]
=
MathExtra
::
dot3
(
camRight
,
normal
);
cNormal
[
1
]
=
MathExtra
::
dot3
(
camUp
,
normal
);
cNormal
[
2
]
=
MathExtra
::
dot3
(
camDir
,
normal
);
depth
=
dist
-
t
;
draw_pixel
(
ix
,
iy
,
depth
,
cNormal
,
surfaceColor
);
}
}
}
/* ---------------------------------------------------------------------- */
void
Image
::
draw_pixel
(
int
ix
,
int
iy
,
double
depth
,
double
*
surface
,
double
*
surfaceColor
)
{
double
diffuseKey
,
diffuseFill
,
diffuseBack
,
specularKey
;
if
(
depth
<
0
||
(
depthBuffer
[
ix
+
iy
*
width
]
>=
0
&&
depth
>=
depthBuffer
[
ix
+
iy
*
width
]))
return
;
depthBuffer
[
ix
+
iy
*
width
]
=
depth
;
// store only the tangent relative to the camera normal (0,0,-1)
surfaceBuffer
[
0
+
ix
*
2
+
iy
*
width
*
2
]
=
surface
[
1
];
surfaceBuffer
[
1
+
ix
*
2
+
iy
*
width
*
2
]
=
-
surface
[
0
];
diffuseKey
=
saturate
(
MathExtra
::
dot3
(
surface
,
keyLightDir
));
diffuseFill
=
saturate
(
MathExtra
::
dot3
(
surface
,
fillLightDir
));
diffuseBack
=
saturate
(
MathExtra
::
dot3
(
surface
,
backLightDir
));
specularKey
=
pow
(
saturate
(
MathExtra
::
dot3
(
surface
,
keyHalfDir
)),
specularHardness
)
*
specularIntensity
;
double
c
[
3
];
c
[
0
]
=
surfaceColor
[
0
]
*
ambientColor
[
0
];
c
[
1
]
=
surfaceColor
[
1
]
*
ambientColor
[
1
];
c
[
2
]
=
surfaceColor
[
2
]
*
ambientColor
[
2
];
c
[
0
]
+=
surfaceColor
[
0
]
*
keyLightColor
[
0
]
*
diffuseKey
;
c
[
1
]
+=
surfaceColor
[
1
]
*
keyLightColor
[
1
]
*
diffuseKey
;
c
[
2
]
+=
surfaceColor
[
2
]
*
keyLightColor
[
2
]
*
diffuseKey
;
c
[
0
]
+=
keyLightColor
[
0
]
*
specularKey
;
c
[
1
]
+=
keyLightColor
[
1
]
*
specularKey
;
c
[
2
]
+=
keyLightColor
[
2
]
*
specularKey
;
c
[
0
]
+=
surfaceColor
[
0
]
*
fillLightColor
[
0
]
*
diffuseFill
;
c
[
1
]
+=
surfaceColor
[
1
]
*
fillLightColor
[
1
]
*
diffuseFill
;
c
[
2
]
+=
surfaceColor
[
2
]
*
fillLightColor
[
2
]
*
diffuseFill
;
c
[
0
]
+=
surfaceColor
[
0
]
*
backLightColor
[
0
]
*
diffuseBack
;
c
[
1
]
+=
surfaceColor
[
1
]
*
backLightColor
[
1
]
*
diffuseBack
;
c
[
2
]
+=
surfaceColor
[
2
]
*
backLightColor
[
2
]
*
diffuseBack
;
c
[
0
]
=
saturate
(
c
[
0
]);
c
[
1
]
=
saturate
(
c
[
1
]);
c
[
2
]
=
saturate
(
c
[
2
]);
imageBuffer
[
0
+
ix
*
3
+
iy
*
width
*
3
]
=
static_cast
<
int
>
(
c
[
0
]
*
255.0
);
imageBuffer
[
1
+
ix
*
3
+
iy
*
width
*
3
]
=
static_cast
<
int
>
(
c
[
1
]
*
255.0
);
imageBuffer
[
2
+
ix
*
3
+
iy
*
width
*
3
]
=
static_cast
<
int
>
(
c
[
2
]
*
255.0
);
}
/* ---------------------------------------------------------------------- */
void
Image
::
compute_SSAO
()
{
// used for rasterizing the spheres
double
delTheta
=
2.0
*
MY_PI
/
SSAOSamples
;
// typical neighborhood value for shading
double
pixelWidth
=
(
tanPerPixel
>
0
)
?
tanPerPixel
:
-
tanPerPixel
/
zoom
;
int
pixelRadius
=
(
int
)
trunc
(
SSAORadius
/
pixelWidth
+
0.5
);
int
x
,
y
,
s
;
int
hPart
=
height
/
nprocs
;
int
index
=
me
*
hPart
*
width
;
for
(
y
=
me
*
hPart
;
y
<
(
me
+
1
)
*
hPart
;
y
++
)
{
for
(
x
=
0
;
x
<
width
;
x
++
,
index
++
)
{
double
cdepth
=
depthBuffer
[
index
];
if
(
cdepth
<
0
)
{
continue
;
}
double
sx
=
surfaceBuffer
[
index
*
2
+
0
];
double
sy
=
surfaceBuffer
[
index
*
2
+
1
];
double
sin_t
=
-
sqrt
(
sx
*
sx
+
sy
*
sy
);
double
theta
=
random
->
uniform
()
*
SSAOJitter
;
double
ao
=
0.0
;
for
(
s
=
0
;
s
<
SSAOSamples
;
s
++
)
{
double
hx
=
cos
(
theta
);
double
hy
=
sin
(
theta
);
theta
+=
delTheta
;
// multiply by z cross surface tangent
// so that dot (aka cos) works here
double
scaled_sin_t
=
sin_t
*
(
hx
*
sy
+
hy
*
sx
);
// Bresenham's line algorithm to march over depthBuffer
int
dx
=
static_cast
<
int
>
(
hx
*
pixelRadius
);
int
dy
=
static_cast
<
int
>
(
hy
*
pixelRadius
);
int
ex
=
x
+
dx
;
if
(
ex
<
0
)
{
ex
=
0
;
}
if
(
ex
>=
width
)
{
ex
=
width
-
1
;
}
int
ey
=
y
+
dy
;
if
(
ey
<
0
)
{
ey
=
0
;
}
if
(
ey
>=
height
)
{
ey
=
height
-
1
;
}
double
delta
;
int
small
,
large
;
double
lenIncr
;
if
(
fabs
(
hx
)
>
fabs
(
hy
))
{
small
=
(
hx
>
0
)
?
1
:
-
1
;
large
=
(
hy
>
0
)
?
width
:
-
width
;
delta
=
fabs
(
hy
/
hx
);
}
else
{
small
=
(
hy
>
0
)
?
width
:
-
width
;
large
=
(
hx
>
0
)
?
1
:
-
1
;
delta
=
fabs
(
hx
/
hy
);
}
lenIncr
=
sqrt
(
1
+
delta
*
delta
)
*
pixelWidth
;
// initialize with one step
// because the center point doesn't need testing
int
end
=
ex
+
ey
*
width
;
int
ind
=
index
+
small
;
double
len
=
lenIncr
;
double
err
=
delta
;
if
(
err
>=
1.0
)
{
ind
+=
large
;
err
-=
1.0
;
}
double
minPeak
=
-
1
;
double
peakLen
=
0.0
;
int
stepsTaken
=
1
;
while
((
small
>
0
&&
ind
<=
end
)
||
(
small
<
0
&&
ind
>=
end
))
{
if
(
ind
<
0
||
ind
>=
(
width
*
height
))
{
break
;
}
// cdepth - depthBuffer B/C we want it in the negative z direction
if
(
minPeak
<
0
||
(
depthBuffer
[
ind
]
>=
0
&&
depthBuffer
[
ind
]
<
minPeak
))
{
minPeak
=
depthBuffer
[
ind
];
peakLen
=
len
;
}
ind
+=
small
;
len
+=
lenIncr
;
err
+=
delta
;
if
(
err
>=
1.0
)
{
ind
+=
large
;
err
-=
1.0
;
}
stepsTaken
++
;
}
if
(
peakLen
>
0
)
{
double
h
=
atan
((
cdepth
-
minPeak
)
/
peakLen
);
ao
+=
saturate
(
sin
(
h
)
-
scaled_sin_t
);
}
else
{
ao
+=
saturate
(
-
scaled_sin_t
);
}
}
ao
/=
(
double
)
SSAOSamples
;
double
c
[
3
];
c
[
0
]
=
(
double
)
(
*
(
unsigned
char
*
)
&
imageBuffer
[
index
*
3
+
0
]);
c
[
1
]
=
(
double
)
(
*
(
unsigned
char
*
)
&
imageBuffer
[
index
*
3
+
1
]);
c
[
2
]
=
(
double
)
(
*
(
unsigned
char
*
)
&
imageBuffer
[
index
*
3
+
2
]);
c
[
0
]
*=
(
1.0
-
ao
);
c
[
1
]
*=
(
1.0
-
ao
);
c
[
2
]
*=
(
1.0
-
ao
);
imageBuffer
[
index
*
3
+
0
]
=
(
int
)
c
[
0
];
imageBuffer
[
index
*
3
+
1
]
=
(
int
)
c
[
1
];
imageBuffer
[
index
*
3
+
2
]
=
(
int
)
c
[
2
];
}
}
}
/* ---------------------------------------------------------------------- */
void
Image
::
write_JPG
(
FILE
*
fp
)
{
#ifdef LAMMPS_JPEG
struct
jpeg_compress_struct
cinfo
;
struct
jpeg_error_mgr
jerr
;
JSAMPROW
row_pointer
;
cinfo
.
err
=
jpeg_std_error
(
&
jerr
);
jpeg_create_compress
(
&
cinfo
);
jpeg_stdio_dest
(
&
cinfo
,
fp
);
cinfo
.
image_width
=
width
;
cinfo
.
image_height
=
height
;
cinfo
.
input_components
=
3
;
cinfo
.
in_color_space
=
JCS_RGB
;
jpeg_set_defaults
(
&
cinfo
);
jpeg_set_quality
(
&
cinfo
,
100
,
1
);
jpeg_start_compress
(
&
cinfo
,
1
);
while
(
cinfo
.
next_scanline
<
cinfo
.
image_height
)
{
row_pointer
=
(
JSAMPROW
)
&
writeBuffer
[(
cinfo
.
image_height
-
1
-
cinfo
.
next_scanline
)
*
3
*
width
];
jpeg_write_scanlines
(
&
cinfo
,
&
row_pointer
,
1
);
}
jpeg_finish_compress
(
&
cinfo
);
jpeg_destroy_compress
(
&
cinfo
);
#endif
}
/* ---------------------------------------------------------------------- */
void
Image
::
write_PPM
(
FILE
*
fp
)
{
fprintf
(
fp
,
"P6
\n
%d %d
\n
255
\n
"
,
width
,
height
);
int
x
,
y
;
for
(
y
=
height
-
1
;
y
>=
0
;
y
--
)
for
(
x
=
0
;
x
<
width
;
x
++
)
fprintf
(
fp
,
"%c%c%c"
,
writeBuffer
[
0
+
x
*
3
+
y
*
width
*
3
],
writeBuffer
[
1
+
x
*
3
+
y
*
width
*
3
],
writeBuffer
[
2
+
x
*
3
+
y
*
width
*
3
]);
}
/* ----------------------------------------------------------------------
define a color map
args = lo hi style delta N entry1 entry2 ... entryN as defined by caller
return 1 if any error in args, else return 0
------------------------------------------------------------------------- */
int
Image
::
colormap
(
int
narg
,
char
**
arg
)
{
if
(
!
islower
(
arg
[
0
][
0
]))
{
mlo
=
NUMERIC
;
mlovalue
=
atof
(
arg
[
0
]);
}
else
if
(
strcmp
(
arg
[
0
],
"min"
)
==
0
)
mlo
=
MINVALUE
;
else
return
1
;
if
(
!
islower
(
arg
[
1
][
0
]))
{
mhi
=
NUMERIC
;
mhivalue
=
atof
(
arg
[
1
]);
}
else
if
(
strcmp
(
arg
[
1
],
"max"
)
==
0
)
mhi
=
MAXVALUE
;
else
return
1
;
if
(
mlo
==
NUMERIC
&&
mhi
==
NUMERIC
&&
mlovalue
>=
mhivalue
)
return
1
;
if
(
strlen
(
arg
[
2
])
!=
2
)
return
1
;
if
(
arg
[
2
][
0
]
==
'c'
)
mstyle
=
CONTINUOUS
;
else
if
(
arg
[
2
][
0
]
==
'd'
)
mstyle
=
DISCRETE
;
else
if
(
arg
[
2
][
0
]
==
's'
)
mstyle
=
SEQUENTIAL
;
else
return
1
;
if
(
arg
[
2
][
1
]
==
'a'
)
mrange
=
ABSOLUTE
;
else
if
(
arg
[
2
][
1
]
==
'f'
)
mrange
=
FRACTIONAL
;
else
return
1
;
if
(
mstyle
==
SEQUENTIAL
)
{
mbinsize
=
atof
(
arg
[
3
]);
if
(
mbinsize
<=
0.0
)
return
1
;
mbinsizeinv
=
1.0
/
mbinsize
;
}
nentry
=
atoi
(
arg
[
4
]);
if
(
nentry
<
1
)
return
1
;
mentry
=
new
MapEntry
[
nentry
];
int
n
=
5
;
for
(
int
i
=
0
;
i
<
nentry
;
i
++
)
{
if
(
mstyle
==
CONTINUOUS
)
{
if
(
n
+
2
>
narg
)
return
1
;
if
(
!
islower
(
arg
[
n
][
0
]))
{
mentry
[
i
].
single
=
NUMERIC
;
mentry
[
i
].
svalue
=
atof
(
arg
[
n
]);
}
else
if
(
strcmp
(
arg
[
n
],
"min"
)
==
0
)
mentry
[
i
].
single
=
MINVALUE
;
else
if
(
strcmp
(
arg
[
n
],
"max"
)
==
0
)
mentry
[
i
].
single
=
MAXVALUE
;
else
return
1
;
mentry
[
i
].
color
=
color2rgb
(
arg
[
n
+
1
]);
n
+=
2
;
}
else
if
(
mstyle
==
DISCRETE
)
{
if
(
n
+
3
>
narg
)
return
1
;
if
(
!
islower
(
arg
[
n
][
0
]))
{
mentry
[
i
].
lo
=
NUMERIC
;
mentry
[
i
].
lvalue
=
atof
(
arg
[
n
]);
}
else
if
(
strcmp
(
arg
[
n
],
"min"
)
==
0
)
mentry
[
i
].
single
=
MINVALUE
;
else
if
(
strcmp
(
arg
[
n
],
"max"
)
==
0
)
mentry
[
i
].
single
=
MAXVALUE
;
else
return
1
;
if
(
!
islower
(
arg
[
n
+
1
][
0
]))
{
mentry
[
i
].
hi
=
NUMERIC
;
mentry
[
i
].
hvalue
=
atof
(
arg
[
n
+
1
]);
}
else
if
(
strcmp
(
arg
[
n
+
1
],
"min"
)
==
0
)
mentry
[
i
].
single
=
MINVALUE
;
else
if
(
strcmp
(
arg
[
n
+
1
],
"max"
)
==
0
)
mentry
[
i
].
single
=
MAXVALUE
;
else
return
1
;
mentry
[
i
].
color
=
color2rgb
(
arg
[
n
+
2
]);
n
+=
3
;
}
else
if
(
mstyle
==
SEQUENTIAL
)
{
if
(
n
+
1
>
narg
)
return
1
;
mentry
[
i
].
color
=
color2rgb
(
arg
[
n
]);
n
+=
1
;
}
if
(
mentry
[
i
].
color
==
NULL
)
return
1
;
}
if
(
mstyle
==
CONTINUOUS
)
{
if
(
nentry
<
2
)
return
1
;
if
(
mentry
[
0
].
single
!=
MINVALUE
||
mentry
[
nentry
-
1
].
single
!=
MAXVALUE
)
return
1
;
for
(
int
i
=
2
;
i
<
nentry
-
1
;
i
++
)
if
(
mentry
[
i
].
svalue
<=
mentry
[
i
-
1
].
svalue
)
return
1
;
}
else
if
(
mstyle
==
DISCRETE
)
{
if
(
nentry
<
1
)
return
1
;
if
(
mentry
[
nentry
-
1
].
lo
!=
MINVALUE
||
mentry
[
nentry
-
1
].
hi
!=
MAXVALUE
)
return
1
;
}
else
if
(
mstyle
==
SEQUENTIAL
)
{
if
(
nentry
<
1
)
return
1
;
}
return
0
;
}
/* ----------------------------------------------------------------------
add a new color to username and userrgb
redefine RGB values in userrgb if name already exists
return 1 if RGB values are invalid, else return 0
------------------------------------------------------------------------- */
int
Image
::
addcolor
(
char
*
name
,
double
r
,
double
g
,
double
b
)
{
int
icolor
;
for
(
icolor
=
0
;
icolor
<
ncolors
;
icolor
++
)
if
(
strcmp
(
name
,
username
[
icolor
])
==
0
)
break
;
if
(
icolor
==
ncolors
)
{
username
=
(
char
**
)
memory
->
srealloc
(
username
,(
ncolors
+
1
)
*
sizeof
(
char
*
),
"image:username"
);
memory
->
grow
(
userrgb
,
ncolors
+
1
,
3
,
"image:userrgb"
);
ncolors
++
;
}
int
n
=
strlen
(
name
)
+
1
;
username
[
icolor
]
=
new
char
[
n
];
strcpy
(
username
[
icolor
],
name
);
if
(
r
<
0.0
||
r
>
1.0
||
g
<
0.0
||
g
>
1.0
||
b
<
0.0
||
b
>
1.0
)
return
1
;
userrgb
[
icolor
][
0
]
=
r
;
userrgb
[
icolor
][
1
]
=
g
;
userrgb
[
icolor
][
2
]
=
b
;
return
0
;
}
/* ----------------------------------------------------------------------
convert value into an RGB color via color map
------------------------------------------------------------------------- */
double
*
Image
::
value2color
(
double
value
)
{
double
lo
,
hi
;
value
=
MAX
(
value
,
locurrent
);
value
=
MIN
(
value
,
hicurrent
);
if
(
mrange
==
FRACTIONAL
)
{
if
(
locurrent
==
hicurrent
)
value
=
0.0
;
else
value
=
(
value
-
locurrent
)
/
(
hicurrent
-
locurrent
);
lo
=
0.0
;
hi
=
1.0
;
}
else
{
lo
=
locurrent
;
hi
=
hicurrent
;
}
if
(
mstyle
==
CONTINUOUS
)
{
for
(
int
i
=
0
;
i
<
nentry
-
1
;
i
++
)
if
(
value
>=
mentry
[
i
].
svalue
&&
value
<=
mentry
[
i
+
1
].
svalue
)
{
double
fraction
=
(
value
-
mentry
[
i
].
svalue
)
/
(
mentry
[
i
+
1
].
svalue
-
mentry
[
i
].
svalue
);
interpolate
[
0
]
=
mentry
[
i
].
color
[
0
]
+
fraction
*
(
mentry
[
i
+
1
].
color
[
0
]
-
mentry
[
i
].
color
[
0
]);
interpolate
[
1
]
=
mentry
[
i
].
color
[
1
]
+
fraction
*
(
mentry
[
i
+
1
].
color
[
1
]
-
mentry
[
i
].
color
[
1
]);
interpolate
[
2
]
=
mentry
[
i
].
color
[
2
]
+
fraction
*
(
mentry
[
i
+
1
].
color
[
2
]
-
mentry
[
i
].
color
[
2
]);
return
interpolate
;
}
}
else
if
(
mstyle
==
DISCRETE
)
{
for
(
int
i
=
0
;
i
<
nentry
;
i
++
)
if
(
value
>=
mentry
[
i
].
lvalue
&&
value
<=
mentry
[
i
].
hvalue
)
return
mentry
[
i
].
color
;
}
else
{
int
ibin
=
static_cast
<
int
>
((
value
-
lo
)
*
mbinsizeinv
);
return
mentry
[
ibin
%
nentry
].
color
;
}
return
NULL
;
}
/* ----------------------------------------------------------------------
search the list of color names for the string color
return a pointer to the 3 floating point RGB values
search user-defined color names first, then the list of NCOLORS names
------------------------------------------------------------------------- */
double
*
Image
::
color2rgb
(
const
char
*
color
,
int
index
)
{
static
const
char
*
name
[
NCOLORS
]
=
{
"aliceblue"
,
"antiquewhite"
,
"aqua"
,
"aquamarine"
,
"azure"
,
"beige"
,
"bisque"
,
"black"
,
"blanchedalmond"
,
"blue"
,
"blueviolet"
,
"brown"
,
"burlywood"
,
"cadetblue"
,
"chartreuse"
,
"chocolate"
,
"coral"
,
"cornflowerblue"
,
"cornsilk"
,
"crimson"
,
"cyan"
,
"darkblue"
,
"darkcyan"
,
"darkgoldenrod"
,
"darkgray"
,
"darkgreen"
,
"darkkhaki"
,
"darkmagenta"
,
"darkolivegreen"
,
"darkorange"
,
"darkorchid"
,
"darkred"
,
"darksalmon"
,
"darkseagreen"
,
"darkslateblue"
,
"darkslategray"
,
"darkturquoise"
,
"darkviolet"
,
"deeppink"
,
"deepskyblue"
,
"dimgray"
,
"dodgerblue"
,
"firebrick"
,
"floralwhite"
,
"forestgreen"
,
"fuchsia"
,
"gainsboro"
,
"ghostwhite"
,
"gold"
,
"goldenrod"
,
"gray"
,
"green"
,
"greenyellow"
,
"honeydew"
,
"hotpink"
,
"indianred"
,
"indigo"
,
"ivory"
,
"khaki"
,
"lavender"
,
"lavenderblush"
,
"lawngreen"
,
"lemonchiffon"
,
"lightblue"
,
"lightcoral"
,
"lightcyan"
,
"lightgoldenrodyellow"
,
"lightgreen"
,
"lightgrey"
,
"lightpink"
,
"lightsalmon"
,
"lightseagreen"
,
"lightskyblue"
,
"lightslategray"
,
"lightsteelblue"
,
"lightyellow"
,
"lime"
,
"limegreen"
,
"linen"
,
"magenta"
,
"maroon"
,
"mediumaquamarine"
,
"mediumblue"
,
"mediumorchid"
,
"mediumpurple"
,
"mediumseagreen"
,
"mediumslateblue"
,
"mediumspringgreen"
,
"mediumturquoise"
,
"mediumvioletred"
,
"midnightblue"
,
"mintcream"
,
"mistyrose"
,
"moccasin"
,
"navajowhite"
,
"navy"
,
"oldlace"
,
"olive"
,
"olivedrab"
,
"orange"
,
"orangered"
,
"orchid"
,
"palegoldenrod"
,
"palegreen"
,
"paleturquoise"
,
"palevioletred"
,
"papayawhip"
,
"peachpuff"
,
"peru"
,
"pink"
,
"plum"
,
"powderblue"
,
"purple"
,
"red"
,
"rosybrown"
,
"royalblue"
,
"saddlebrown"
,
"salmon"
,
"sandybrown"
,
"seagreen"
,
"seashell"
,
"sienna"
,
"silver"
,
"skyblue"
,
"slateblue"
,
"slategray"
,
"snow"
,
"springgreen"
,
"steelblue"
,
"tan"
,
"teal"
,
"thistle"
,
"tomato"
,
"turquoise"
,
"violet"
,
"wheat"
,
"white"
,
"whitesmoke"
,
"yellow"
,
"yellowgreen"
};
static
double
rgb
[
NCOLORS
][
3
]
=
{
{
240
/
255.0
,
248
/
255.0
,
255
/
255.0
},
{
250
/
255.0
,
235
/
255.0
,
215
/
255.0
},
{
0
/
255.0
,
255
/
255.0
,
255
/
255.0
},
{
127
/
255.0
,
255
/
255.0
,
212
/
255.0
},
{
240
/
255.0
,
255
/
255.0
,
255
/
255.0
},
{
245
/
255.0
,
245
/
255.0
,
220
/
255.0
},
{
255
/
255.0
,
228
/
255.0
,
196
/
255.0
},
{
0
/
255.0
,
0
/
255.0
,
0
/
255.0
},
{
255
/
255.0
,
255
/
255.0
,
205
/
255.0
},
{
0
/
255.0
,
0
/
255.0
,
255
/
255.0
},
{
138
/
255.0
,
43
/
255.0
,
226
/
255.0
},
{
165
/
255.0
,
42
/
255.0
,
42
/
255.0
},
{
222
/
255.0
,
184
/
255.0
,
135
/
255.0
},
{
95
/
255.0
,
158
/
255.0
,
160
/
255.0
},
{
127
/
255.0
,
255
/
255.0
,
0
/
255.0
},
{
210
/
255.0
,
105
/
255.0
,
30
/
255.0
},
{
255
/
255.0
,
127
/
255.0
,
80
/
255.0
},
{
100
/
255.0
,
149
/
255.0
,
237
/
255.0
},
{
255
/
255.0
,
248
/
255.0
,
220
/
255.0
},
{
220
/
255.0
,
20
/
255.0
,
60
/
255.0
},
{
0
/
255.0
,
255
/
255.0
,
255
/
255.0
},
{
0
/
255.0
,
0
/
255.0
,
139
/
255.0
},
{
0
/
255.0
,
139
/
255.0
,
139
/
255.0
},
{
184
/
255.0
,
134
/
255.0
,
11
/
255.0
},
{
169
/
255.0
,
169
/
255.0
,
169
/
255.0
},
{
0
/
255.0
,
100
/
255.0
,
0
/
255.0
},
{
189
/
255.0
,
183
/
255.0
,
107
/
255.0
},
{
139
/
255.0
,
0
/
255.0
,
139
/
255.0
},
{
85
/
255.0
,
107
/
255.0
,
47
/
255.0
},
{
255
/
255.0
,
140
/
255.0
,
0
/
255.0
},
{
153
/
255.0
,
50
/
255.0
,
204
/
255.0
},
{
139
/
255.0
,
0
/
255.0
,
0
/
255.0
},
{
233
/
255.0
,
150
/
255.0
,
122
/
255.0
},
{
143
/
255.0
,
188
/
255.0
,
143
/
255.0
},
{
72
/
255.0
,
61
/
255.0
,
139
/
255.0
},
{
47
/
255.0
,
79
/
255.0
,
79
/
255.0
},
{
0
/
255.0
,
206
/
255.0
,
209
/
255.0
},
{
148
/
255.0
,
0
/
255.0
,
211
/
255.0
},
{
255
/
255.0
,
20
/
255.0
,
147
/
255.0
},
{
0
/
255.0
,
191
/
255.0
,
255
/
255.0
},
{
105
/
255.0
,
105
/
255.0
,
105
/
255.0
},
{
30
/
255.0
,
144
/
255.0
,
255
/
255.0
},
{
178
/
255.0
,
34
/
255.0
,
34
/
255.0
},
{
255
/
255.0
,
250
/
255.0
,
240
/
255.0
},
{
34
/
255.0
,
139
/
255.0
,
34
/
255.0
},
{
255
/
255.0
,
0
/
255.0
,
255
/
255.0
},
{
220
/
255.0
,
220
/
255.0
,
220
/
255.0
},
{
248
/
255.0
,
248
/
255.0
,
255
/
255.0
},
{
255
/
255.0
,
215
/
255.0
,
0
/
255.0
},
{
218
/
255.0
,
165
/
255.0
,
32
/
255.0
},
{
128
/
255.0
,
128
/
255.0
,
128
/
255.0
},
{
0
/
255.0
,
128
/
255.0
,
0
/
255.0
},
{
173
/
255.0
,
255
/
255.0
,
47
/
255.0
},
{
240
/
255.0
,
255
/
255.0
,
240
/
255.0
},
{
255
/
255.0
,
105
/
255.0
,
180
/
255.0
},
{
205
/
255.0
,
92
/
255.0
,
92
/
255.0
},
{
75
/
255.0
,
0
/
255.0
,
130
/
255.0
},
{
255
/
255.0
,
240
/
255.0
,
240
/
255.0
},
{
240
/
255.0
,
230
/
255.0
,
140
/
255.0
},
{
230
/
255.0
,
230
/
255.0
,
250
/
255.0
},
{
255
/
255.0
,
240
/
255.0
,
245
/
255.0
},
{
124
/
255.0
,
252
/
255.0
,
0
/
255.0
},
{
255
/
255.0
,
250
/
255.0
,
205
/
255.0
},
{
173
/
255.0
,
216
/
255.0
,
230
/
255.0
},
{
240
/
255.0
,
128
/
255.0
,
128
/
255.0
},
{
224
/
255.0
,
255
/
255.0
,
255
/
255.0
},
{
250
/
255.0
,
250
/
255.0
,
210
/
255.0
},
{
144
/
255.0
,
238
/
255.0
,
144
/
255.0
},
{
211
/
255.0
,
211
/
255.0
,
211
/
255.0
},
{
255
/
255.0
,
182
/
255.0
,
193
/
255.0
},
{
255
/
255.0
,
160
/
255.0
,
122
/
255.0
},
{
32
/
255.0
,
178
/
255.0
,
170
/
255.0
},
{
135
/
255.0
,
206
/
255.0
,
250
/
255.0
},
{
119
/
255.0
,
136
/
255.0
,
153
/
255.0
},
{
176
/
255.0
,
196
/
255.0
,
222
/
255.0
},
{
255
/
255.0
,
255
/
255.0
,
224
/
255.0
},
{
0
/
255.0
,
255
/
255.0
,
0
/
255.0
},
{
50
/
255.0
,
205
/
255.0
,
50
/
255.0
},
{
250
/
255.0
,
240
/
255.0
,
230
/
255.0
},
{
255
/
255.0
,
0
/
255.0
,
255
/
255.0
},
{
128
/
255.0
,
0
/
255.0
,
0
/
255.0
},
{
102
/
255.0
,
205
/
255.0
,
170
/
255.0
},
{
0
/
255.0
,
0
/
255.0
,
205
/
255.0
},
{
186
/
255.0
,
85
/
255.0
,
211
/
255.0
},
{
147
/
255.0
,
112
/
255.0
,
219
/
255.0
},
{
60
/
255.0
,
179
/
255.0
,
113
/
255.0
},
{
123
/
255.0
,
104
/
255.0
,
238
/
255.0
},
{
0
/
255.0
,
250
/
255.0
,
154
/
255.0
},
{
72
/
255.0
,
209
/
255.0
,
204
/
255.0
},
{
199
/
255.0
,
21
/
255.0
,
133
/
255.0
},
{
25
/
255.0
,
25
/
255.0
,
112
/
255.0
},
{
245
/
255.0
,
255
/
255.0
,
250
/
255.0
},
{
255
/
255.0
,
228
/
255.0
,
225
/
255.0
},
{
255
/
255.0
,
228
/
255.0
,
181
/
255.0
},
{
255
/
255.0
,
222
/
255.0
,
173
/
255.0
},
{
0
/
255.0
,
0
/
255.0
,
128
/
255.0
},
{
253
/
255.0
,
245
/
255.0
,
230
/
255.0
},
{
128
/
255.0
,
128
/
255.0
,
0
/
255.0
},
{
107
/
255.0
,
142
/
255.0
,
35
/
255.0
},
{
255
/
255.0
,
165
/
255.0
,
0
/
255.0
},
{
255
/
255.0
,
69
/
255.0
,
0
/
255.0
},
{
218
/
255.0
,
112
/
255.0
,
214
/
255.0
},
{
238
/
255.0
,
232
/
255.0
,
170
/
255.0
},
{
152
/
255.0
,
251
/
255.0
,
152
/
255.0
},
{
175
/
255.0
,
238
/
255.0
,
238
/
255.0
},
{
219
/
255.0
,
112
/
255.0
,
147
/
255.0
},
{
255
/
255.0
,
239
/
255.0
,
213
/
255.0
},
{
255
/
255.0
,
239
/
255.0
,
213
/
255.0
},
{
205
/
255.0
,
133
/
255.0
,
63
/
255.0
},
{
255
/
255.0
,
192
/
255.0
,
203
/
255.0
},
{
221
/
255.0
,
160
/
255.0
,
221
/
255.0
},
{
176
/
255.0
,
224
/
255.0
,
230
/
255.0
},
{
128
/
255.0
,
0
/
255.0
,
128
/
255.0
},
{
255
/
255.0
,
0
/
255.0
,
0
/
255.0
},
{
188
/
255.0
,
143
/
255.0
,
143
/
255.0
},
{
65
/
255.0
,
105
/
255.0
,
225
/
255.0
},
{
139
/
255.0
,
69
/
255.0
,
19
/
255.0
},
{
250
/
255.0
,
128
/
255.0
,
114
/
255.0
},
{
244
/
255.0
,
164
/
255.0
,
96
/
255.0
},
{
46
/
255.0
,
139
/
255.0
,
87
/
255.0
},
{
255
/
255.0
,
245
/
255.0
,
238
/
255.0
},
{
160
/
255.0
,
82
/
255.0
,
45
/
255.0
},
{
192
/
255.0
,
192
/
255.0
,
192
/
255.0
},
{
135
/
255.0
,
206
/
255.0
,
235
/
255.0
},
{
106
/
255.0
,
90
/
255.0
,
205
/
255.0
},
{
112
/
255.0
,
128
/
255.0
,
144
/
255.0
},
{
255
/
255.0
,
250
/
255.0
,
250
/
255.0
},
{
0
/
255.0
,
255
/
255.0
,
127
/
255.0
},
{
70
/
255.0
,
130
/
255.0
,
180
/
255.0
},
{
210
/
255.0
,
180
/
255.0
,
140
/
255.0
},
{
0
/
255.0
,
128
/
255.0
,
128
/
255.0
},
{
216
/
255.0
,
191
/
255.0
,
216
/
255.0
},
{
253
/
255.0
,
99
/
255.0
,
71
/
255.0
},
{
64
/
255.0
,
224
/
255.0
,
208
/
255.0
},
{
238
/
255.0
,
130
/
255.0
,
238
/
255.0
},
{
245
/
255.0
,
222
/
255.0
,
179
/
255.0
},
{
255
/
255.0
,
255
/
255.0
,
255
/
255.0
},
{
245
/
255.0
,
245
/
255.0
,
245
/
255.0
},
{
255
/
255.0
,
255
/
255.0
,
0
/
255.0
},
{
154
/
255.0
,
205
/
255.0
,
50
/
255.0
}
};
if
(
index
)
return
rgb
[
index
-
1
];
for
(
int
i
=
0
;
i
<
ncolors
;
i
++
)
if
(
strcmp
(
color
,
username
[
i
])
==
0
)
return
userrgb
[
i
];
for
(
int
i
=
0
;
i
<
NCOLORS
;
i
++
)
if
(
strcmp
(
color
,
name
[
i
])
==
0
)
return
rgb
[
i
];
return
NULL
;
}
/* ----------------------------------------------------------------------
return number of default colors
------------------------------------------------------------------------- */
int
Image
::
default_colors
()
{
return
NCOLORS
;
}
/* ----------------------------------------------------------------------
search the list of element names for the string element
return a pointer to the 3 floating point RGB values
this list is used by AtomEye and is taken from its Mendeleyev.c file
------------------------------------------------------------------------- */
double
*
Image
::
element2color
(
char
*
element
)
{
static
const
char
*
name
[
NELEMENTS
]
=
{
"H"
,
"He"
,
"Li"
,
"Be"
,
"B"
,
"C"
,
"N"
,
"O"
,
"F"
,
"Ne"
,
"Na"
,
"Mg"
,
"Al"
,
"Si"
,
"P"
,
"S"
,
"Cl"
,
"Ar"
,
"K"
,
"Ca"
,
"Sc"
,
"Ti"
,
"V"
,
"Cr"
,
"Mn"
,
"Fe"
,
"Co"
,
"Ni"
,
"Cu"
,
"Zn"
,
"Ga"
,
"Ge"
,
"As"
,
"Se"
,
"Br"
,
"Kr"
,
"Rb"
,
"Sr"
,
"Y"
,
"Zr"
,
"Nb"
,
"Mo"
,
"Tc"
,
"Ru"
,
"Rh"
,
"Pd"
,
"Ag"
,
"Cd"
,
"In"
,
"Sn"
,
"Sb"
,
"Te"
,
"I"
,
"Xe"
,
"Cs"
,
"Ba"
,
"La"
,
"Ce"
,
"Pr"
,
"Nd"
,
"Pm"
,
"Sm"
,
"Eu"
,
"Gd"
,
"Tb"
,
"Dy"
,
"Ho"
,
"Er"
,
"Tm"
,
"Yb"
,
"Lu"
,
"Hf"
,
"Ta"
,
"W"
,
"Re"
,
"Os"
,
"Ir"
,
"Pt"
,
"Au"
,
"Hg"
,
"Tl"
,
"Pb"
,
"Bi"
,
"Po"
,
"At"
,
"Rn"
,
"Fr"
,
"Ra"
,
"Ac"
,
"Th"
,
"Pa"
,
"U"
,
"Np"
,
"Pu"
,
"Am"
,
"Cm"
,
"Bk"
,
"Cf"
,
"Es"
,
"Fm"
,
"Md"
,
"No"
,
"Lr"
,
"Rf"
,
"Db"
,
"Sg"
,
"Bh"
,
"Hs"
,
"Mt"
};
static
double
rgb
[
NELEMENTS
][
3
]
=
{
{
0.8
,
0.8
,
0.8
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.7
,
0.7
,
0.7
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.9
,
0.4
,
0
},
{
0.35
,
0.35
,
0.35
},
{
0.2
,
0.2
,
0.8
},
{
0.8
,
0.2
,
0.2
},
{
0.7
,
0.85
,
0.45
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6
,
0.6
,
0.6
},
{
0.6
,
0.6
,
0.7
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6901960784
,
0.768627451
,
0.8705882353
},
{
0.1
,
0.7
,
0.3
},
{
0.95
,
0.9
,
0.2
},
{
0.15
,
0.5
,
0.1
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.5
,
0.5
,
0.5
},
{
0.8
,
0.8
,
0.7
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0
,
0.8
,
0
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.5176470588
,
0.5764705882
,
0.6529411765
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.257254902
,
0.2666666667
,
0.271372549
},
{
0.95
,
0.7900735294
,
0.01385869565
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.9
,
0
,
1
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
1
,
1
,
0.3
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.5
,
0.08
,
0.12
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.5
,
0.1
,
0.5
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.8
,
0.8
,
0
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
1
,
0.8431372549
,
0
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.9
,
0.8
,
0
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.8
,
0.2
,
0.2
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.1
,
0.7
,
0.3
},
{
0.1
,
0.3
,
0.7
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.9
,
0.8
,
0
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
},
{
0.6431372549
,
0.6666666667
,
0.6784313725
}
};
for
(
int
i
=
0
;
i
<
NELEMENTS
;
i
++
)
if
(
strcmp
(
element
,
name
[
i
])
==
0
)
return
rgb
[
i
];
return
NULL
;
}
/* ----------------------------------------------------------------------
search the list of element names for the string element
return a pointer to the 3 floating point RGB values
this list is used by AtomEye and is taken from its Mendeleyev.c file
------------------------------------------------------------------------- */
double
Image
::
element2diam
(
char
*
element
)
{
static
const
char
*
name
[
NELEMENTS
]
=
{
"H"
,
"He"
,
"Li"
,
"Be"
,
"B"
,
"C"
,
"N"
,
"O"
,
"F"
,
"Ne"
,
"Na"
,
"Mg"
,
"Al"
,
"Si"
,
"P"
,
"S"
,
"Cl"
,
"Ar"
,
"K"
,
"Ca"
,
"Sc"
,
"Ti"
,
"V"
,
"Cr"
,
"Mn"
,
"Fe"
,
"Co"
,
"Ni"
,
"Cu"
,
"Zn"
,
"Ga"
,
"Ge"
,
"As"
,
"Se"
,
"Br"
,
"Kr"
,
"Rb"
,
"Sr"
,
"Y"
,
"Zr"
,
"Nb"
,
"Mo"
,
"Tc"
,
"Ru"
,
"Rh"
,
"Pd"
,
"Ag"
,
"Cd"
,
"In"
,
"Sn"
,
"Sb"
,
"Te"
,
"I"
,
"Xe"
,
"Cs"
,
"Ba"
,
"La"
,
"Ce"
,
"Pr"
,
"Nd"
,
"Pm"
,
"Sm"
,
"Eu"
,
"Gd"
,
"Tb"
,
"Dy"
,
"Ho"
,
"Er"
,
"Tm"
,
"Yb"
,
"Lu"
,
"Hf"
,
"Ta"
,
"W"
,
"Re"
,
"Os"
,
"Ir"
,
"Pt"
,
"Au"
,
"Hg"
,
"Tl"
,
"Pb"
,
"Bi"
,
"Po"
,
"At"
,
"Rn"
,
"Fr"
,
"Ra"
,
"Ac"
,
"Th"
,
"Pa"
,
"U"
,
"Np"
,
"Pu"
,
"Am"
,
"Cm"
,
"Bk"
,
"Cf"
,
"Es"
,
"Fm"
,
"Md"
,
"No"
,
"Lr"
,
"Rf"
,
"Db"
,
"Sg"
,
"Bh"
,
"Hs"
,
"Mt"
};
static
double
diameter
[
NELEMENTS
]
=
{
0.35
,
1.785
,
1.45
,
1.05
,
0.85
,
0.72
,
0.65
,
0.6
,
0.5
,
1.5662
,
1.8
,
1.5
,
1.4255
,
1.07
,
1
,
1
,
1
,
1.8597
,
2.2
,
1.8
,
1.6
,
1.4
,
1.51995
,
1.44225
,
1.4
,
1.43325
,
1.35
,
1.35
,
1.278
,
1.35
,
1.3
,
1.25
,
1.15
,
1.15
,
1.15
,
2.0223
,
2.35
,
2
,
1.8
,
1.55
,
1.6504
,
1.3872
,
1.35
,
1.3
,
1.35
,
1.4
,
1.6
,
1.55
,
1.55
,
1.45
,
1.45
,
1.4
,
1.4
,
2.192
,
2.6
,
2.15
,
1.95
,
1.85
,
1.85
,
1.85
,
1.85
,
1.85
,
1.85
,
1.8
,
1.75
,
1.75
,
1.75
,
1.75
,
1.75
,
1.75
,
1.75
,
1.55
,
1.6529
,
1.5826
,
1.35
,
1.3
,
1.35
,
1.35
,
1.35
,
1.5
,
1.9
,
1.8
,
1.6
,
1.9
,
1.6
,
1.0
,
1.0
,
2.15
,
1.95
,
1.8
,
1.8
,
1.75
,
1.75
,
1.75
,
1.75
,
1.0
,
1.0
,
1.6
,
1.6
,
1.0
,
1.0
,
1.0
,
1.0
,
1.0
,
1.6
,
1.0
,
1.0
,
1.0
,
1.0
};
for
(
int
i
=
0
;
i
<
NELEMENTS
;
i
++
)
if
(
strcmp
(
element
,
name
[
i
])
==
0
)
return
diameter
[
i
];
return
0.0
;
}
Event Timeline
Log In to Comment