home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
p
/
ply15dat.zip
/
LIB.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-10-17
|
60KB
|
1,733 lines
/*
* lib.c - a library of vector operations, a random number generator, and
* object output routines.
*
* Version: 2.2 (11/17/87)
* Author: Eric Haines, 3D/Eye, Inc.
*
* Modified: 1 October 1992
* Alexander R. Enzmann
*
* I made quite a few changes in order to support multiple raytracers,
* with the hopes that this library would become even more useful than
* it already is.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "def.h"
#include "lib.h"
/* Here are some local variables that are used to control things like
the current output file, current texture, ... */
static FILE *outfile = stdout;
static char *texture_name = NULL;
static int texture_count = 0;
static int format = OUTPUT_POVRAY;
static int u_resolution = OUTPUT_RESOLUTION;
static int v_resolution = OUTPUT_RESOLUTION;
static COORD4 view_from = {0.0, 0.0, -5.0, 1.0};
static COORD4 view_at = {0.0, 0.0, 0.0, 1.0};
static COORD4 view_up = {0.0, 0.0, 1.0, 1.0};
static double view_angle = 45;
static double view_hither = 0.001;
static double view_aspect = 1.0;
static int view_resx = 128;
static int view_resy = 128;
static COORD4 bk_color = {0.0, 0.0, 0.0, 0.0};
static COORD4 fg_color = {0.0, 0.0, 0.0, 0.0};
/* Display a matrix */
static void
show_tx(descrip, tx)
char *descrip;
MATRIX tx;
{
int i, j, offset = strlen(descrip);
printf("%s", descrip);
printf("[ %10.6g %10.6g %10.6g %10.6g]\n",
tx[0][0], tx[0][1], tx[0][2], tx[0][3]);
for (i=1;i<4;i++) {
for (j=0;j<offset;j++)
printf(" ");
printf("[ %10.6g %10.6g %10.6g %10.6g]\n",
tx[i][0], tx[i][1], tx[i][2], tx[i][3]);
}
}
/*
* Normalize the vector (X,Y,Z) so that X*X + Y*Y + Z*Z = 1.
*
* The normalization divisor is returned. If the divisor is zero, no
* normalization occurs.
*
*/
double
lib_normalize_coord3(cvec)
COORD4 *cvec;
{
double divisor;
divisor = sqrt( (double)DOT_PRODUCT( (*cvec), (*cvec) ) ) ;
if (divisor != 0.0 ) {
cvec->x /= divisor;
cvec->y /= divisor;
cvec->z /= divisor;
}
return divisor;
}
/*
* Set all matrix elements to zero.
*/
void
lib_zero_matrix(mx)
MATRIX mx;
{
long i, j;
for (i=0;i<4;++i)
for (j=0;j<4;++j)
mx[i][j] = 0.0;
}
/*
* Create identity matrix.
*/
void
lib_create_identity_matrix(mx)
MATRIX mx;
{
int i;
lib_zero_matrix(mx);
for (i=0;i<4;++i)
mx[i][i] = 1.0;
}
/*
* Create a rotation matrix along the given axis by the given angle in radians.
*/
void
lib_create_rotate_matrix(mx, axis, angle)
MATRIX mx;
int axis;
double angle;
{
double cosine, sine;
lib_zero_matrix(mx);
cosine = cos((double)angle);
sine = sin((double)angle);
switch (axis) {
case X_AXIS:
mx[0][0] = 1.0;
mx[1][1] = cosine;
mx[2][2] = cosine;
mx[1][2] = sine;
mx[2][1] = -sine;
break ;
case Y_AXIS:
mx[1][1] = 1.0;
mx[0][0] = cosine;
mx[2][2] = cosine;
mx[2][0] = sine;
mx[0][2] = -sine;
break;
case Z_AXIS:
mx[2][2] = 1.0;
mx[0][0] = cosine;
mx[1][1] = cosine;
mx[0][1] = sine;
mx[1][0] = -sine;
break;
}
mx[3][3] = 1.0;
}
/*
* Create a rotation matrix along the given axis by the given angle in radians.
* The axis is a set of direction cosines.
*/
void
lib_create_axis_rotate_matrix(mx, rvec, angle)
MATRIX mx;
COORD4 *rvec;
double angle;
{
COORD4 axis;
double cosine, one_minus_cosine, sine;
COPY_COORD(axis, (*rvec));
cosine = cos((double)angle);
sine = sin((double)angle);
one_minus_cosine = 1.0 - cosine;
mx[0][0] = SQR(axis.x) + (1.0 - SQR(axis.x)) * cosine;
mx[0][1] = axis.x * axis.y * one_minus_cosine + axis.z * sine;
mx[0][2] = axis.x * axis.z * one_minus_cosine - axis.y * sine;
mx[0][3] = 0.0;
mx[1][0] = axis.x * axis.y * one_minus_cosine - axis.z * sine;
mx[1][1] = SQR(axis.y) + (1.0 - SQR(axis.y)) * cosine;
mx[1][2] = axis.y * axis.z * one_minus_cosine + axis.x * sine;
mx[1][3] = 0.0;
mx[2][0] = axis.x * axis.z * one_minus_cosine + axis.y * sine;
mx[2][1] = axis.y * axis.z * one_minus_cosine - axis.x * sine;
mx[2][2] = SQR(axis.z) + (1.0 - SQR(axis.z)) * cosine;
mx[2][3] = 0.0;
mx[3][0] = 0.0;
mx[3][1] = 0.0;
mx[3][2] = 0.0;
mx[3][3] = 1.0;
}
/* Create translation matrix */
void
lib_create_translate_matrix(mx, vec)
MATRIX mx;
COORD4 *vec;
{
int i;
lib_create_identity_matrix(mx);
mx[3][0] = vec->x;
mx[3][1] = vec->y;
mx[3][2] = vec->z;
}
/* Create scaling matrix */
void
lib_create_scale_matrix(mx, vec)
MATRIX mx;
COORD4 *vec;
{
int i;
lib_zero_matrix(mx);
mx[0][0] = vec->x;
mx[1][1] = vec->y;
mx[2][2] = vec->z;
}
/* Given a point and a direction, find the transform that brings a point
in a canonical coordinate system into a coordinate system defined by
that position and direction. Both the forward and inverse transform
matrices are calculated. */
void
lib_create_canonical_matrix(trans, itrans, origin, up)
MATRIX trans, itrans;
COORD4 *origin;
COORD4 *up;
{
MATRIX trans1, trans2;
COORD4 tmpv;
double ang;
/* Translate "origin" to <0, 0, 0> */
SET_COORD(tmpv, -origin->x, -origin->y, -origin->z);
lib_create_translate_matrix(trans1, &tmpv);
/* Determine the axis to rotate about */
if (fabs(up->z) == 1.0)
SET_COORD4(tmpv, 1.0, 0.0, 0.0, 1.0)
else
SET_COORD4(tmpv, -up->y, up->x, 0.0, 1.0)
lib_normalize_coord3(&tmpv);
ang = acos(up->z);
/* Calculate the forward matrix */
lib_create_axis_rotate_matrix(trans2, &tmpv, -ang);
lib_matrix_multiply(trans, trans1, trans2);
/* Calculate the inverse transform */
lib_create_axis_rotate_matrix(trans1, &tmpv, ang);
lib_create_translate_matrix(trans2, origin);
lib_matrix_multiply(itrans, trans1, trans2);
}
/*
* Multiply a 4 element vector by a matrix.
*/
void
lib_transform_coord(vres, vec, mx)
COORD4 *vres, *vec;
MATRIX mx;
{
vres->x = vec->x*mx[0][0]+vec->y*mx[1][0]+vec->z*mx[2][0]+vec->w*mx[3][0];
vres->y = vec->x*mx[0][1]+vec->y*mx[1][1]+vec->z*mx[2][1]+vec->w*mx[3][1];
vres->z = vec->x*mx[0][2]+vec->y*mx[1][2]+vec->z*mx[2][2]+vec->w*mx[3][2];
vres->w = vec->x*mx[0][3]+vec->y*mx[1][3]+vec->z*mx[2][3]+vec->w*mx[3][3];
}
/*
* Multiply two 4x4 matrices.
*/
void
lib_matrix_multiply(mxres, mx1, mx2)
MATRIX mxres, mx1, mx2;
{
int i, j;
for (i=0;i<4;i++)
for (j=0;j<4;j++)
mxres[i][j] = mx1[i][0]*mx2[0][j] + mx1[i][1]*mx2[1][j] +
mx1[i][2]*mx2[2][j] + mx1[i][3]*mx2[3][j];
}
/*
* Rotate a vector pointing towards the major-axis faces (i.e. the major-axis
* component of the vector is defined as the largest value) 90 degrees to
* another cube face. Mod_face is a face number.
*
* If the routine is called six times, with mod_face=0..5, the vector will be
* rotated to each face of a cube. Rotations are:
* mod_face = 0 mod 3, +Z axis rotate
* mod_face = 1 mod 3, +X axis rotate
* mod_face = 2 mod 3, -Y axis rotate
*/
void
lib_rotate_cube_face(vec, major_axis, mod_face)
COORD4 *vec;
int major_axis, mod_face;
{
double swap;
mod_face = (mod_face+major_axis) % 3 ;
if (mod_face == 0) {
swap = vec->x;
vec->x = -vec->y;
vec->y = swap;
}
else if (mod_face == 1) {
swap = vec->y;
vec->y = -vec->z;
vec->z = swap;
}
else {
swap = vec->x;
vec->x = -vec->z;
vec->z = swap;
}
}
/*
* Portable gaussian random number generator (from "Numerical Recipes", GASDEV)
* Returns a uniform random deviate between 0.0 and 1.0. 'iseed' must be
* less than M1 to avoid repetition, and less than (2**31-C1)/A1 [= 300718]
* to avoid overflow.
*/
#define M1 134456
#define IA1 8121
#define IC1 28411
#define RM1 1.0/M1
double
lib_gauss_rand(iseed)
long iseed;
{
double fac, v1, v2, r;
long ix1, ix2;
ix2 = iseed;
do {
ix1 = (IC1+ix2*IA1) % M1;
ix2 = (IC1+ix1*IA1) % M1;
v1 = ix1 * 2.0 * RM1 - 1.0;
v2 = ix2 * 2.0 * RM1 - 1.0;
r = v1*v1 + v2*v2;
} while ( r >= 1.0 );
fac = sqrt((double)(-2.0 * log((double)r) / r));
return v1 * fac;
}
/*
* Routines to set/reset the various output parameters
*/
void
lib_set_output_file(new_outfile)
FILE *new_outfile;
{
if (new_outfile == NULL)
outfile = stdout;
else
outfile = new_outfile;
}
void
lib_set_default_texture(default_texture)
char *default_texture;
{
texture_name = default_texture;
}
void
lib_set_raytracer(default_tracer)
int default_tracer;
{
format = default_tracer;
}
void
lib_set_polygonalization(u_steps, v_steps)
int u_steps, v_steps;
{
if (u_steps > 0 && v_steps > 0) {
u_resolution = u_steps;
v_resolution = v_steps;
}
}
/* OUTPUT ROUTINES */
/*
* Output viewpoint location. The parameters are:
* From: the eye location.
* At: a position to be at the center of the image. A.k.a. "lookat"
* Up: a vector defining which direction is up.
*
* Note that no assumptions are made about normalizing the data (e.g. the
* from-at distance does not have to be 1). Also, vectors are not
* required to be perpendicular to each other.
*
* For all databases some viewing parameters are always the same:
*
* Viewing angle is defined as from the center of top pixel row to bottom
* pixel row and left column to right column.
* Yon is "at infinity."
* Resolution is always 512 x 512.
*/
void
lib_output_viewpoint(from, at, up,
fov_angle, aspect_ratio, hither,
resx, resy)
COORD4 *from, *at, *up;
double fov_angle, aspect_ratio, hither;
int resx, resy;
{
COORD4 viewvec, rightvec;
double frustrumheight, frustrumwidth;
switch (format) {
case OUTPUT_VIDEO:
/* For now we are just saving the values - what should be done
is to generate the perspective transformation matrix for the
given values to the screen. */
COPY_COORD4(view_from, *from);
COPY_COORD4(view_at, *at);
COPY_COORD4(view_up, *up);
view_angle = fov_angle;
view_hither = hither;
view_resx = resx;
view_resy = resy;
view_aspect = aspect_ratio;
break;
case OUTPUT_NFF:
fprintf(outfile, "v\n");
fprintf(outfile, "from %g %g %g\n", from->x, from->y, from->z);
fprintf(outfile, "at %g %g %g\n", at->x, at->y, at->z);
fprintf(outfile, "up %g %g %g\n", up->x, up->y, up->z);
fprintf(outfile, "angle %g\n", fov_angle);
fprintf(outfile, "hither %g\n", hither);
fprintf(outfile, "resolution %d %d\n", resx, resy);
break;
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
/* Lets get a set of vectors that are all at right angles to each
other that describe the view given. */
lib_normalize_coord3(up);
SUB3_COORD(viewvec, *at, *from);
lib_normalize_coord3(&viewvec);
CROSS(rightvec, *up, viewvec);
lib_normalize_coord3(&rightvec);
CROSS(*up, viewvec, rightvec);
lib_normalize_coord3(up);
/* Calculate the height of the view frustrum in world coordinates.
and then scale the right and up vectors appropriately. */
frustrumheight = 2.0 * tan(PI * fov_angle / 360.0);
frustrumwidth = aspect_ratio * frustrumheight;
up->x *= frustrumheight;
up->y *= frustrumheight;
up->z *= frustrumheight;
rightvec.x *= frustrumwidth;
rightvec.y *= frustrumwidth;
rightvec.z *= frustrumwidth;
fprintf(outfile, "camera {\n");
if (format == OUTPUT_POVRAY) {
fprintf(outfile, " location <%g %g %g>\n",
from->x, from->y, from->z);
fprintf(outfile, " direction <%g %g %g>\n",
viewvec.x, viewvec.y, viewvec.z);
fprintf(outfile, " right <%g %g %g>\n",
rightvec.x, rightvec.y, rightvec.z);
fprintf(outfile, " up <%g %g %g>\n",
up->x, up->y, up->z);
}
else {
fprintf(outfile, " location <%g, %g, %g>\n",
from->x, from->y, from->z);
fprintf(outfile, " direction <%g, %g, %g>\n",
viewvec.x, viewvec.y, viewvec.z);
fprintf(outfile, " right <%g, %g, %g>\n",
rightvec.x, rightvec.y, rightvec.z);
fprintf(outfile, " up <%g, %g, %g>\n",
up->x, up->y, up->z);
}
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "viewpoint {\n");
fprintf(outfile, " from <%g, %g, %g>\n", from->x, from->y, from->z);
fprintf(outfile, " at <%g, %g, %g>\n", at->x, at->y, at->z);
fprintf(outfile, " up <%g, %g, %g>\n", up->x, up->y, up->z);
fprintf(outfile, " angle %g\n", fov_angle);
fprintf(outfile, " aspect %g\n", aspect_ratio);
fprintf(outfile, " hither %g\n", hither);
fprintf(outfile, " resolution %d, %d\n", resx, resy);
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
fprintf(outfile, "studio = {\n");
fprintf(outfile, " from = %g %g %g;\n", from->x, from->y, from->z);
fprintf(outfile, " at = %g %g %g;\n", at->x, at->y, at->z);
fprintf(outfile, " up = %g %g %g;\n", up->x, up->y, up->z);
fprintf(outfile, " angle = %g;\n", fov_angle);
fprintf(outfile, " aspect = %g;\n", aspect_ratio);
fprintf(outfile, " resolution = %d %d;\n", resx, resy);
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
fprintf(outfile, "OBSERVER = (\n");
fprintf(outfile, " loc = (%g,%g,%g),\n", from->x, from->y, from->z);
fprintf(outfile, " lookat = (%g,%g,%g),\n", at->x, at->y, at->z);
fprintf(outfile, " up = (%g,%g,%g) )\n", up->x, up->y, up->z);
fprintf(outfile, "FOC_LENGTH = %g\n",
35.0 / tan(PI * fov_angle / 360.0));
fprintf(outfile, "DEFAULT (\n");
fprintf(outfile, " aspect = %g,\n", 6.0 * aspect_ratio / 7.0);
fprintf(outfile, " x_res = %d, y_res = %d )\n", resx, resy);
/* QRT insists on having the output file as part of the data text */
fprintf(outfile, "FILE_NAME = qrt.tga\n");
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "eyep %g %g %g\n", from->x, from->y, from->z);
fprintf(outfile, "lookp %g %g %g\n", at->x, at->y, at->z);
fprintf(outfile, "up %g %g %g\n", up->x, up->y, up->z);
fprintf(outfile, "fov %g %g\n", aspect_ratio * fov_angle, fov_angle);
fprintf(outfile, "screen %d %d\n", resx, resy);
fprintf(outfile, "sample 1 nojitter\n");
break;
}
}
/*
* Output light. A light is defined by position. All lights have the same
* intensity.
*
*/
void
lib_output_light(center_pt)
COORD4 *center_pt;
{
double lscale;
if (center_pt->w != 0.0)
lscale = center_pt->w;
else
lscale = 1.0;
switch (format) {
case OUTPUT_VIDEO:
/* Not currently doing anything with lights */
break;
case OUTPUT_NFF:
fprintf(outfile, "l %g %g %g\n",
center_pt->x, center_pt->y, center_pt->z ) ;
break;
case OUTPUT_POVRAY:
fprintf(outfile, "object { ");
fprintf(outfile,
"light_source { <%g %g %g> color red %g green %g blue %g }",
center_pt->x, center_pt->y, center_pt->z,
lscale, lscale, lscale);
fprintf(outfile, "}\n");
break;
case OUTPUT_POVRAY_15:
fprintf(outfile, "object { ");
fprintf(outfile,
"light_source { <%g, %g, %g> color red %g green %g blue %g }",
center_pt->x, center_pt->y, center_pt->z,
lscale, lscale, lscale);
fprintf(outfile, "}\n");
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "light <%g, %g, %g>, <%g, %g, %g>\n",
lscale, lscale, lscale,
center_pt->x, center_pt->y, center_pt->z);
break;
case OUTPUT_VIVID:
fprintf(outfile, "light = {type=point; position = %g %g %g;",
center_pt->x, center_pt->y, center_pt->z );
fprintf(outfile, " color = %g %g %g;}\n",
lscale, lscale, lscale);
break;
case OUTPUT_QRT:
fprintf(outfile, "LAMP ( loc = (%g,%g,%g), dist = 0, radius = 1,",
center_pt->x, center_pt->y, center_pt->z );
fprintf(outfile, " amb = (%g,%g,%g) )\n",
lscale, lscale, lscale);
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "light %g point %g %g %g\n",
center_pt->w, center_pt->x, center_pt->y, center_pt->z);
break;
}
}
/*
* Output background color. A color is simply RGB (monitor dependent, but
* that's life).
*/
void
lib_output_background_color(color)
COORD4 *color;
{
switch (format) {
case OUTPUT_VIDEO:
COPY_COORD4(bk_color, *color);
break;
case OUTPUT_NFF:
fprintf(outfile, "b %g %g %g\n", color->x, color->y, color->z);
break;
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
/* POV-Ray 1.0/1.5 do not support a background color */
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "background <%g, %g, %g>\n",
color->x, color->y, color->z);
break;
case OUTPUT_VIVID:
/* Vivid insists on putting the background into the studio */
fprintf(outfile, "studio = { background = %g %g %g; }\n",
color->x, color->y, color->z);
break;
case OUTPUT_QRT:
fprintf(outfile, "SKY ( horiz = (%g,%g,%g), zenith = (%g,%g,%g),",
color->x, color->y, color->z,
color->x, color->y, color->z);
fprintf(outfile, " dither = 0 )\n");
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "background %g %g %g\n",
color->x, color->y, color->z);
break;
}
}
/*
* Output color and shading parameters for all following objects
*
* For POV-Ray and Polyray, a character string will be returned that
* identified this texture. The default texture will be updated with
* the name generated by this function.
*
* Meaning of the color and shading parameters:
* color = surface color
* ka = ambient component
* kd = diffuse component
* ks = amount contributed from the reflected direction
* shine = contribution from specular highlights
* ang = angle at which the specular highlight falls to 50% of maximum
* t = amount from the refracted direction
* i_of_r = index of refraction of the surface
*
*/
char *
lib_output_color(color, ka, kd, ks, shine, ang, t, i_of_r)
COORD4 *color;
double ka, kd, ks, shine, ang, t, i_of_r;
{
char *txname = NULL;
double phong_pow;
/* Calculate the Phong coefficient */
phong_pow = PI * ang / 180.0;
if (phong_pow <= 0.0)
phong_pow = 100000.0;
else if (phong_pow >= (PI/4.0))
phong_pow = 0.000001;
else
phong_pow = -(log(2.0) / log(cos(2.0 * phong_pow)));
switch (format) {
case OUTPUT_VIDEO:
COPY_COORD4(fg_color, *color);
break;
case OUTPUT_NFF:
fprintf(outfile, "f %g %g %g %g %g %g %g %g\n",
color->x, color->y, color->z, kd, ks, phong_pow, t, i_of_r);
break;
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
txname = (char *)malloc(7*sizeof(char));
if (txname == NULL) {
fprintf(outfile, "Failed to allocate texture name %d\n",
texture_count);
exit(1);
}
sprintf(txname, "txt%03d", texture_count++);
txname[6] = '\0';
fprintf(outfile, "#declare %s = texture {\n", txname);
if (format == OUTPUT_POVRAY_15)
fprintf(outfile, " pigment {\n");
if (t > 0)
fprintf(outfile, " color red %g green %g blue %g alpha 1.0\n",
color->x, color->y, color->z);
else
fprintf(outfile, " color red %g green %g blue %g\n",
color->x, color->y, color->z);
if (format == OUTPUT_POVRAY_15) {
fprintf(outfile, " }\n");
fprintf(outfile, " finish {\n");
}
fprintf(outfile, " ambient %g\n", ka);
fprintf(outfile, " diffuse %g\n", kd);
if (shine != 0)
fprintf(outfile, " phong %g phong_size %g\n", shine, phong_pow);
if (ks != 0)
fprintf(outfile, " reflection %g\n", ks);
if (t != 0)
fprintf(outfile, " refraction %g ior %g\n", t, i_of_r);
if (format == OUTPUT_POVRAY_15)
fprintf(outfile, " }\n");
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
txname = (char *)malloc(7*sizeof(char));
if (txname == NULL) {
fprintf(outfile, "Failed to allocate texture name %d\n",
texture_count);
exit(1);
}
sprintf(txname, "txt%03d", texture_count++);
txname[6] = '\0';
fprintf(outfile, "define %s\n", txname);
fprintf(outfile, "texture {\n");
fprintf(outfile, " surface {\n");
fprintf(outfile, " ambient <%g, %g, %g>, %g\n",
color->x, color->y, color->z, ka);
fprintf(outfile, " diffuse <%g, %g, %g>, %g\n",
color->x, color->y, color->z, kd);
if (shine != 0) {
fprintf(outfile, " specular white, %g\n", shine);
fprintf(outfile, " microfacet Phong %g\n", ang);
}
if (ks != 0)
fprintf(outfile, " reflection white, %g\n", ks);
if (t != 0)
fprintf(outfile, " transmission white, %g, %g\n", t, i_of_r);
fprintf(outfile, " }\n");
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
fprintf(outfile, "surface = {\n");
fprintf(outfile, " ambient = %g %g %g;\n",
ka * color->x, ka * color->y, ka * color->z, ka);
fprintf(outfile, " diffuse = %g %g %g;\n",
kd * color->x, kd * color->y, kd * color->z, ka);
if (shine != 0)
fprintf(outfile, " shine = %g %g %g %g;\n",
phong_pow, shine, shine, shine);
if (ks != 0)
fprintf(outfile, " specular = %g %g %g;\n", ks, ks, ks);
if (t != 0) {
fprintf(outfile, " transparent = %g %g %g;\n",
t * color->x, t * color->y, t * color->z);
fprintf(outfile, " ior = %g;\n", i_of_r);
}
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
fprintf(outfile, "DEFAULT (\n");
fprintf(outfile, " amb = (%g,%g,%g),\n",
ka * color->x, ka * color->y, ka * color->z, ka);
fprintf(outfile, " diff = (%g,%g,%g),\n",
kd * color->x, kd * color->y, kd * color->z, ka);
fprintf(outfile, " reflect = %g, sreflect = %g,\n",
shine, phong_pow);
fprintf(outfile, " mirror = (%g,%g,%g),\n",
ks * color->x, ks * color->y, ks * color->z);
fprintf(outfile, " trans = (%g,%g,%g), index = %g,\n",
t * color->x, t * color->y, t * color->z, i_of_r);
fprintf(outfile, " dither = 0 )\n");
break;
case OUTPUT_RAYSHADE:
txname = (char *)malloc(7*sizeof(char));
if (txname == NULL) {
fprintf(outfile, "Failed to allocate texture name %d\n",
texture_count);
exit(1);
}
sprintf(txname, "txt%03d", texture_count++);
txname[6] = '\0';
fprintf(outfile, "surface %s\n", txname);
fprintf(outfile, " ambient %g %g %g\n",
ka * color->x, ka * color->y, ka * color->z);
fprintf(outfile, " diffuse %g %g %g\n",
kd * color->x, kd * color->y, kd * color->z);
if (shine != 0) {
fprintf(outfile, " specular %g %g %g\n", shine, shine, shine);
fprintf(outfile, " specpow %g\n", phong_pow);
}
if (ks != 0)
fprintf(outfile, " reflect %g\n", ks);
if (t != 0)
fprintf(outfile, " transp %g index %g\n", t, i_of_r);
break;
}
texture_name = txname;
return txname;
}
void
lib_output_polygon_cylcone(base_pt, apex_pt, curve_format)
COORD4 *base_pt, *apex_pt;
int curve_format;
{
double angle, delta_angle, divisor;
COORD4 axis, dir, norm_axis, start_norm;
COORD4 norm[4], vert[4], start_radius[4];
MATRIX mx;
int i;
SUB3_COORD(axis, (*apex_pt), (*base_pt));
COPY_COORD(norm_axis, axis);
lib_normalize_coord3(&norm_axis);
SET_COORD(dir, 0, 0, 1);
CROSS(start_norm, axis, dir);
start_norm.w = 0.0;
divisor = lib_normalize_coord3(&start_norm);
if (ABS(divisor) < EPSILON) {
SET_COORD(dir, 1, 0, 0);
CROSS(start_norm, axis, dir);
lib_normalize_coord3(&start_norm);
}
start_radius[0].x = start_norm.x * base_pt->w;
start_radius[0].y = start_norm.y * base_pt->w;
start_radius[0].z = start_norm.z * base_pt->w;
start_radius[0].w = 0.0;
ADD3_COORD(vert[0], (*base_pt), start_radius[0]);
start_radius[1].x = start_norm.x * apex_pt->w;
start_radius[1].y = start_norm.y * apex_pt->w;
start_radius[1].z = start_norm.z * apex_pt->w;
start_radius[1].w = 0.0;
ADD3_COORD(vert[1], (*apex_pt), start_radius[1]);
COPY_COORD4(norm[0], start_norm);
COPY_COORD4(norm[1], start_norm);
delta_angle = 2.0 * PI / (double)(2*u_resolution);
for (i=1,angle=0.0;i<=2*u_resolution;++i,angle+=delta_angle) {
lib_create_axis_rotate_matrix(mx, &norm_axis, angle);
lib_transform_coord(&vert[2], &start_radius[1], mx);
ADD2_COORD(vert[2], *apex_pt);
lib_transform_coord(&norm[2], &start_norm, mx);
lib_output_polypatch(3, vert, norm);
COPY_COORD4(vert[1], vert[2]);
norm[1] = norm[2];
lib_transform_coord(&vert[2], &start_radius[0], mx);
ADD2_COORD(vert[2], *base_pt);
lib_output_polypatch(3, vert, norm);
COPY_COORD4(vert[0], vert[2]);
COPY_COORD4(norm[0], norm[2]);
}
}
/*
* Output cylinder or cone. A cylinder is defined as having a radius and an
* axis defined by two points, which also define the top and bottom edge of the
* cylinder. A cone is defined similarly, the difference being that the apex
* and base radii are different. The apex radius is defined as being smaller
* than the base radius. Note that the surface exists without endcaps.
*
* If format=OUTPUT_CURVES, output the cylinder/cone in format:
* "c"
* base.x base.y base.z base_radius
* apex.x apex.y apex.z apex_radius
*
* If the format=OUTPUT_POLYGONS, the surface is polygonalized and output.
* (4*OUTPUT_RESOLUTION) polygons are output as rectangles by
* lib_output_polypatch.
*/
void
lib_output_cylcone(base_pt, apex_pt, curve_format)
COORD4 *base_pt, *apex_pt;
int curve_format;
{
double angle, divisor;
COORD4 axis, dir, norm_axis, start_norm;
COORD4 lip_norm[4], lip_pt[4], start_radius[4];
MATRIX mx;
long num_pol;
double len, cottheta, xang, yang;
if (curve_format == OUTPUT_CURVES) {
switch (format) {
case OUTPUT_VIDEO:
lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
break;
case OUTPUT_NFF:
fprintf(outfile, "c\n" ) ;
fprintf(outfile, "%g %g %g %g\n",
base_pt->x, base_pt->y, base_pt->z, base_pt->w ) ;
fprintf(outfile, "%g %g %g %g\n",
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w ) ;
break;
case OUTPUT_POVRAY:
/* Since POV-Ray uses infinite primitives, we will start
with a cone aligned with the z-axis (QCone_Z) and figure
out how to clip and scale it to match what we want */
if (apex_pt->w < base_pt->w) {
/* Put the bigger end at the top */
COPY_COORD4(axis, *base_pt);
COPY_COORD4(*base_pt, *apex_pt);
COPY_COORD4(*apex_pt, axis);
}
/* Find the axis and axis length */
SUB3_COORD(axis, *apex_pt, *base_pt);
len = lib_normalize_coord3(&axis);
if (len < EPSILON)
/* Degenerate cone/cylinder */
break;
if (ABS(apex_pt->w - base_pt->w) < 0.000001) {
/* Treat this thing as a cylinder */
cottheta = 1.0;
fprintf(outfile, "object {quadric{<1 1 0><0 0 0><0 0 0>-1}\n");
}
else {
/* Determine alignment */
cottheta = len / (apex_pt->w - base_pt->w);
fprintf(outfile, "object {quadric{<1 1 -1><0 0 0><0 0 0>0}\n");
}
fprintf(outfile, " clipped_by {\n");
fprintf(outfile, " intersection {\n");
fprintf(outfile, " plane { <0 0 -1> %g }\n", -base_pt->w);
fprintf(outfile, " plane { <0 0 1> %g }\n", apex_pt->w);
fprintf(outfile, " } }\n");
fprintf(outfile, " translate <0 0 %g>\n", -base_pt->w);
fprintf(outfile, " scale <1 1 %g>\n", cottheta);
len = sqrt(axis.x * axis.x + axis.z * axis.z);
xang = -180.0 * asin(axis.y) / PI;
yang = 180.0 * acos(axis.z / len) / PI;
if (axis.x < 0)
yang = -yang;
fprintf(outfile, " rotate <%g %g 0>\n", xang, yang);
fprintf(outfile, " translate <%g %g %g>\n",
base_pt->x, base_pt->y, base_pt->z);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POVRAY_15:
fprintf(outfile, "object {\n");
fprintf(outfile, " cone { apex <%g, %g, %g> apex_radius %g\n",
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
fprintf(outfile, " base <%g, %g, %g> base_radius %g }\n",
base_pt->x, base_pt->y, base_pt->z, base_pt->w);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "object {");
if (base_pt->w == apex_pt->w)
fprintf(outfile, " cylinder <%g, %g, %g>, <%g, %g, %g>, %g",
base_pt->x, base_pt->y, base_pt->z,
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
else
fprintf(outfile, " cone <%g, %g, %g>, %g, <%g, %g, %g>, %g",
base_pt->x, base_pt->y, base_pt->z, base_pt->w,
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
fprintf(outfile, "cone = {");
fprintf(outfile, " base = %g %g %g; base_radius = %g;\n",
base_pt->x, base_pt->y, base_pt->z, base_pt->w);
fprintf(outfile, " apex = %g %g %g; apex_radius = %g;\n",
apex_pt->x, apex_pt->y, apex_pt->z, apex_pt->w);
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
fprintf(outfile, "BEGIN_BBOX\n");
lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
fprintf(outfile, "END_BBOX\n");
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "cone ");
if (texture_name != NULL)
fprintf(outfile, "%s ", texture_name);
fprintf(outfile, " %g %g %g %g %g %g %g %g\n",
base_pt->w, base_pt->x, base_pt->y, base_pt->z,
apex_pt->w, apex_pt->x, apex_pt->y, apex_pt->z);
break;
}
}
else
lib_output_polygon_cylcone(base_pt, apex_pt, curve_format);
}
void
sq_sphere_val(a1, a2, a3, n, e, u, v, P)
double a1, a2, a3, n, e, u, v;
COORD4 *P;
{
double cu, su, cv, sv;
cu = cos(u); su = sin(u);
cv = cos(v); sv = sin(v);
P->x = a1 * POW(ABS(cv), n) * POW(ABS(cu), e) * SGN(cv) * SGN(cu);
P->y = a2 * POW(ABS(cv), n) * POW(ABS(su), e) * SGN(cv) * SGN(su);
P->z = a3 * POW(ABS(sv), n) * SGN(sv);
}
void
sq_sphere_norm(a1, a2, a3, n, e, u, v, N)
double a1, a2, a3, n, e, u, v;
COORD4 *N;
{
double cu, su, cv, sv;
cu = cos(u); su = sin(u);
cv = cos(v); sv = sin(v);
/* May be some singularities in the values, lets catch them & put
a fudged normal into N */
if (e < 2 || n < 2) {
if (ABS(cu) < 1.0e-3 || ABS(su) < 1.0e-3 ||
ABS(cu) < 1.0e-3 || ABS(su) < 1.0e-3) {
SET_COORD(*N, cu*cv, su*cv, sv);
lib_normalize_coord3(N);
return;
}
}
N->x = a1 * POW(ABS(cv), 2-n) * POW(ABS(cu), 2-e) * SGN(cv) * SGN(cu);
N->y = a2 * POW(ABS(cv), 2-n) * POW(ABS(su), 2-e) * SGN(cv) * SGN(su);
N->z = a3 * POW(ABS(sv), 2-n) * SGN(sv);
lib_normalize_coord3(N);
}
void
lib_output_sq_sphere(center_pt, a1, a2, a3, n, e)
COORD4 *center_pt;
double a1, a2, a3, n, e;
{
int i, j, u_res, v_res;
double u, delta_u, v, delta_v;
COORD4 verts[4], norms[4];
u_res = 4 * u_resolution;
v_res = 4 * v_resolution;
delta_u = 2.0 * PI / (double)u_res;
delta_v = PI / (double)v_res;
for (i=0,u=0.0;i<u_res;i++,u+=delta_u) {
for (j=0,v=-PI/2.0;j<v_res;j++,v+=delta_v) {
if (j == 0) {
sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v+delta_v, &verts[2]);
sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v+delta_v, &norms[2]);
ADD3_COORD(verts[0], verts[0], *center_pt);
ADD3_COORD(verts[1], verts[1], *center_pt);
ADD3_COORD(verts[2], verts[2], *center_pt);
lib_output_polypatch(3, verts, norms);
}
else if (j == v_res-1) {
sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v, &verts[2]);
sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v, &norms[2]);
ADD3_COORD(verts[0], verts[0], *center_pt);
ADD3_COORD(verts[1], verts[1], *center_pt);
ADD3_COORD(verts[2], verts[2], *center_pt);
lib_output_polypatch(3, verts, norms);
}
else {
sq_sphere_val(a1, a2, a3, n, e, u, v, &verts[0]);
sq_sphere_norm(a1, a2, a3, n, e, u, v, &norms[0]);
sq_sphere_val(a1, a2, a3, n, e, u, v+delta_v, &verts[1]);
sq_sphere_norm(a1, a2, a3, n, e, u, v+delta_v, &norms[1]);
sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v+delta_v, &verts[2]);
sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v+delta_v, &norms[2]);
ADD3_COORD(verts[0], verts[0], *center_pt);
ADD3_COORD(verts[1], verts[1], *center_pt);
ADD3_COORD(verts[2], verts[2], *center_pt);
lib_output_polypatch(3, verts, norms);
COPY_COORD(verts[1], verts[2]);
COPY_COORD(norms[1], norms[2]);
sq_sphere_val(a1, a2, a3, n, e, u+delta_u, v, &verts[2]);
sq_sphere_norm(a1, a2, a3, n, e, u+delta_u, v, &norms[2]);
ADD3_COORD(verts[2], verts[2], *center_pt);
lib_output_polypatch(3, verts, norms);
}
}
}
}
void
lib_output_polygon_sphere(center_pt)
COORD4 *center_pt;
{
double angle;
COORD4 edge_norm[3], edge_pt[3];
long num_face, num_edge, num_tri, num_vert;
COORD4 *x_axis, *y_axis, **pt;
COORD4 mid_axis;
MATRIX rot_mx;
long u_pol, v_pol;
/* Allocate storage for the polygon vertices */
x_axis = (COORD4 *)malloc((u_resolution+1) * sizeof(COORD4));
y_axis = (COORD4 *)malloc((v_resolution+1) * sizeof(COORD4));
pt = (COORD4 **)malloc((u_resolution+1) * sizeof(COORD4 *));
if (x_axis == NULL || y_axis == NULL || pt == NULL) {
fprintf(stderr, "Failed to allocate polygon data\n");
exit(1);
}
for (num_edge=0;num_edge<u_resolution+1;num_edge++) {
pt[num_edge] = (COORD4 *)malloc((v_resolution+1) * sizeof(COORD4));
if (pt[num_edge] == NULL) {
fprintf(stderr, "Failed to allocate polygon data\n");
exit(1);
}
}
/* calculate axes used to find grid points */
for (num_edge=0;num_edge<=u_resolution;++num_edge) {
angle = (PI/4.0) * (2.0*(double)num_edge/u_resolution - 1.0);
mid_axis.w = 0.0;
mid_axis.x = 1.0; mid_axis.y = 0.0; mid_axis.z = 0.0;
lib_create_rotate_matrix(rot_mx, Y_AXIS, angle);
lib_transform_coord(&x_axis[num_edge], &mid_axis, rot_mx);
}
for (num_edge=0;num_edge<=v_resolution;++num_edge) {
angle = (PI/4.0) * (2.0*(double)num_edge/v_resolution - 1.0);
mid_axis.w = 0.0;
mid_axis.x = 0.0; mid_axis.y = 1.0; mid_axis.z = 0.0;
lib_create_rotate_matrix(rot_mx, X_AXIS, angle);
lib_transform_coord(&y_axis[num_edge], &mid_axis, rot_mx);
}
/* set up grid of points on +Z sphere surface */
for (u_pol=0;u_pol<=u_resolution;++u_pol) {
for (v_pol=0;v_pol<=u_resolution;++v_pol) {
CROSS(pt[u_pol][v_pol], x_axis[u_pol], y_axis[v_pol]);
lib_normalize_coord3(&pt[u_pol][v_pol]);
pt[u_pol][v_pol].w = 1.0;
}
}
for (num_face=0;num_face<6;++num_face) {
/* transform points to cube face */
for (u_pol=0;u_pol<=u_resolution;++u_pol) {
for (v_pol=0;v_pol<=v_resolution;++v_pol) {
lib_rotate_cube_face(&pt[u_pol][v_pol], Z_AXIS, num_face);
}
}
/* output grid */
for (u_pol=0;u_pol<u_resolution;++u_pol) {
for (v_pol=0;v_pol<v_resolution;++v_pol) {
for (num_tri=0;num_tri<2;++num_tri) {
for (num_edge=0;num_edge<3;++num_edge) {
num_vert = (num_tri*2 + num_edge) % 4;
if (num_vert == 0) {
COPY_COORD4(edge_pt[num_edge], pt[u_pol][v_pol]);
}
else if ( num_vert == 1 ) {
COPY_COORD4(edge_pt[num_edge], pt[u_pol][v_pol+1]);
}
else if ( num_vert == 2 ) {
COPY_COORD4(edge_pt[num_edge], pt[u_pol+1][v_pol+1]);
}
else {
COPY_COORD4(edge_pt[num_edge], pt[u_pol+1][v_pol]);
}
COPY_COORD4(edge_norm[num_edge], edge_pt[num_edge]);
edge_pt[num_edge].x = edge_pt[num_edge].x * center_pt->w +
center_pt->x ;
edge_pt[num_edge].y = edge_pt[num_edge].y * center_pt->w +
center_pt->y ;
edge_pt[num_edge].z = edge_pt[num_edge].z * center_pt->w +
center_pt->z ;
}
lib_output_polypatch(3, edge_pt, edge_norm);
}
}
}
}
/* Release any memory used */
for (num_edge=0;num_edge<u_resolution+1;num_edge++)
free(pt[num_edge]);
free(pt);
free(y_axis);
free(x_axis);
}
/*
* Output sphere. A sphere is defined by a radius and center position.
*
* If format=OUTPUT_CURVES, output the sphere in format:
* "s" center.x center.y center.z radius
*
* If the format=OUTPUT_POLYGONS, the sphere is polygonalized and output.
* The sphere is polygonalized by splitting it into 6 faces (of a cube
* projected onto the sphere) and dividing these faces by equally spaced
* great circles. OUTPUT_RESOLUTION affects the number of great circles.
* (6*2*u_resolution*v_resolution) polygons are output as triangles
* using lib_output_polypatch.
*/
void
lib_output_sphere(center_pt, curve_format)
COORD4 *center_pt;
int curve_format;
{
if (curve_format == OUTPUT_CURVES) {
switch (format) {
case OUTPUT_VIDEO:
lib_output_polygon_sphere(center_pt);
break;
case OUTPUT_NFF:
fprintf(outfile, "s %g %g %g %g\n",
center_pt->x, center_pt->y, center_pt->z, center_pt->w ) ;
break;
case OUTPUT_POVRAY:
fprintf(outfile, "object { sphere { <%g %g %g> %g }",
center_pt->x, center_pt->y, center_pt->z, center_pt->w);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POVRAY_15:
fprintf(outfile, "object { sphere { <%g, %g, %g>, %g }",
center_pt->x, center_pt->y, center_pt->z, center_pt->w);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "object { sphere <%g, %g, %g>, %g",
center_pt->x, center_pt->y, center_pt->z, center_pt->w);
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
fprintf(outfile, "sphere = { center = %g %g %g; radius = %g; }\n",
center_pt->x, center_pt->y, center_pt->z, center_pt->w);
break;
case OUTPUT_QRT:
fprintf(outfile, "sphere ( loc = (%g, %g, %g), radius = %g )\n",
center_pt->x, center_pt->y, center_pt->z, center_pt->w);
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "sphere ");
if (texture_name != NULL)
fprintf(outfile, "%s ", texture_name);
fprintf(outfile, " %g %g %g %g\n",
center_pt->w, center_pt->x, center_pt->y, center_pt->z);
break;
}
}
else
lib_output_polygon_sphere(center_pt);
}
static void
torus_evaluator(trans, theta, phi, r0, r1, vert, norm)
MATRIX trans;
double theta, phi, r0, r1;
COORD4 *vert, *norm;
{
COORD4 v0, v1, tvert, tnorm;
/* Compute the position of the point */
SET_COORD4(tvert, (r0 + r1 * sin(theta)) * cos(phi),
(r0 + r1 * sin(theta)) * sin(phi),
r1 * cos(theta), 1.0);
/* Compute the normal at that point */
SET_COORD(v0, r1*cos(theta)*cos(phi),
r1*cos(theta)*sin(phi),
-r1*sin(theta));
SET_COORD(v1, -(r0+r1*sin(theta))*sin(phi),
(r0+r1*sin(theta))*cos(phi),
0.0);
CROSS(tnorm, v0, v1);
tnorm.w = 0.0;
lib_normalize_coord3(&tnorm);
lib_transform_coord(vert, &tvert, trans);
lib_transform_coord(norm, &tnorm, trans);
}
void
lib_output_polygon_torus(center, normal, iradius, oradius)
COORD4 *center, *normal;
double iradius, oradius;
{
double divisor, u, v, delta_u, delta_v;
MATRIX mx, imx;
int i, j;
COORD4 vert[4], norm[4];
if ((divisor = lib_normalize_coord3(normal)) < 1.0e-8) {
fprintf(stderr, "Bad torus normal\n");
exit(1);
}
lib_create_canonical_matrix(mx, imx, center, normal);
delta_u = 2.0 * PI / (double)u_resolution;
delta_v = 2.0 * PI / (double)v_resolution;
/* Dump out polygons */
for (i=0,u=0.0;i<u_resolution;i++,u+=delta_u) {
for (j=0,v=0.0;j<v_resolution;j++,v+=delta_v) {
torus_evaluator(imx, u, v,
iradius, oradius,
&vert[0], &norm[0]);
torus_evaluator(imx, u, v+delta_v,
iradius, oradius,
&vert[1], &norm[1]);
torus_evaluator(imx, u+delta_u, v+delta_v,
iradius, oradius,
&vert[2], &norm[2]);
lib_output_polypatch(3, vert, norm);
vert[1] = vert[2];
norm[1] = norm[2];
torus_evaluator(imx, u+delta_u, v,
iradius, oradius,
&vert[2], &norm[2]);
lib_output_polypatch(3, vert, norm);
}
}
}
void
lib_output_torus(center, normal, iradius, oradius, curve_format)
COORD4 *center, *normal;
double iradius, oradius;
int curve_format;
{
if (curve_format == OUTPUT_CURVES) {
switch (format) {
case OUTPUT_VIDEO:
case OUTPUT_NFF:
case OUTPUT_VIVID:
case OUTPUT_QRT:
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
lib_output_polygon_torus(center, normal, iradius, oradius);
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "object { torus %g, %g", iradius, oradius);
fprintf(outfile, ", <%g, %g, %g>, <%g, %g, %g>",
center->x, center->y, center->z,
normal->x, normal->y, normal->z);
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "torus ");
if (texture_name != NULL)
fprintf(outfile, "%s ", texture_name);
fprintf(outfile, " %g %g %g %g\n",
iradius, center->x, center->y, center->z);
break;
}
}
else
lib_output_polygon_torus(center, normal, iradius, oradius);
}
/* Output box. A box is defined by a diagonally opposite corners. */
void
lib_output_box(p1, p2)
COORD4 *p1, *p2;
{
COORD4 box_verts[4];
switch (format) {
case OUTPUT_VIDEO:
case OUTPUT_NFF:
case OUTPUT_VIVID:
/* Currently no support in nff for a box object, make polygons */
/* Sides */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
/* Front/Back */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
/* Top/Bottom */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p1->y, p2->z);
SET_COORD(box_verts[2], p2->x, p1->y, p2->z);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p2->y, p1->z);
lib_output_polygon(4, box_verts);
break;
case OUTPUT_POVRAY:
fprintf(outfile, "object { box { <%g %g %g> <%g %g %g> }",
p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POVRAY_15:
fprintf(outfile, "object { box { <%g, %g, %g>, <%g, %g, %g> }",
p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "object { box <%g, %g, %g>, <%g, %g, %g>",
p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
fprintf(outfile, "BEGIN_BBOX\n");
/* Currently no support in nff for a box object, make polygons */
/* Sides */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
/* Front/Back */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p2->x, p2->y, p1->z);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p1->x, p1->y, p2->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p1->y, p2->z);
lib_output_polygon(4, box_verts);
/* Top/Bottom */
SET_COORD(box_verts[0], p1->x, p1->y, p1->z);
SET_COORD(box_verts[1], p1->x, p1->y, p2->z);
SET_COORD(box_verts[2], p2->x, p1->y, p2->z);
SET_COORD(box_verts[3], p2->x, p1->y, p1->z);
lib_output_polygon(4, box_verts);
SET_COORD(box_verts[3], p1->x, p2->y, p1->z);
SET_COORD(box_verts[2], p1->x, p2->y, p2->z);
SET_COORD(box_verts[1], p2->x, p2->y, p2->z);
SET_COORD(box_verts[0], p2->x, p2->y, p1->z);
lib_output_polygon(4, box_verts);
fprintf(outfile, "END_BBOX\n");
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "box ");
if (texture_name != NULL)
fprintf(outfile, "%s ", texture_name);
fprintf(outfile, " %g %g %g %g %g %g\n",
p1->x, p1->y, p1->z, p2->x, p2->y, p2->z);
break;
}
}
/*
* Output polygon. A polygon is defined by a set of vertices. With these
* databases, a polygon is defined to have all points coplanar. A polygon has
* only one side, with the order of the vertices being counterclockwise as you
* face the polygon (right-handed coordinate system).
*
* The output format is always:
* "p" total_vertices
* vert1.x vert1.y vert1.z
* [etc. for total_vertices polygons]
*
*/
void
lib_output_polygon(tot_vert, vert)
int tot_vert;
COORD4 *vert;
{
int num_vert, i, j;
COORD4 x, tvert[3];
/* First lets do a couple of checks to see if this is a valid polygon */
for (i=0;i<tot_vert;i++) {
/* If there are two adjacent coordinates that degenerate then
collapse them down to one */
SUB3_COORD(x, vert[i], vert[(i+1)%tot_vert]);
if (lib_normalize_coord3(&x) < 1.0e-8) {
for (j=i;j<tot_vert-1;j++)
memcpy(&tvert[j], &tvert[j+1], sizeof(COORD4));
tot_vert--;
}
}
if (tot_vert < 3)
/* No such thing as a poly that only has two sides */
return;
switch (format) {
case OUTPUT_VIDEO:
/* Step through each segment of the polygon, projecting it
onto the screen. */
break;
case OUTPUT_NFF:
fprintf(outfile, "p %d\n", tot_vert);
for (num_vert=0;num_vert<tot_vert;++num_vert)
fprintf(outfile, "%g %g %g\n",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
break;
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
/* No support in POV-Ray for an arbitrary polygon, we make the
assumption that |hs polygon is convex, and split it into
triangles */
COPY_COORD(tvert[0], vert[0]);
for (i=1;i<tot_vert-1;i++) {
COPY_COORD(tvert[1], vert[i]);
COPY_COORD(tvert[2], vert[i+1]);
fprintf(outfile, "object { triangle { ");
for (num_vert=0;num_vert<3;++num_vert)
if (format == OUTPUT_POVRAY)
fprintf(outfile, "<%g %g %g> ",
tvert[num_vert].x, tvert[num_vert].y,
tvert[num_vert].z);
else {
fprintf(outfile, "<%g, %g, %g>",
tvert[num_vert].x, tvert[num_vert].y,
tvert[num_vert].z);
if (num_vert < 2)
fprintf(outfile, ",");
fprintf(outfile, " ");
}
if (texture_name != NULL)
fprintf(outfile, "} texture { %s }", texture_name);
fprintf(outfile, " }\n");
}
break;
case OUTPUT_POLYRAY:
fprintf(outfile, "object { polygon %d,", tot_vert);
for (num_vert = 0; num_vert < tot_vert; num_vert++) {
fprintf(outfile, " <%g, %g, %g>",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
if (num_vert < tot_vert-1)
fprintf(outfile, ", ");
}
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
fprintf(outfile, "polygon = { points = %d;", tot_vert);
for (num_vert = 0; num_vert < tot_vert; num_vert++)
fprintf(outfile, " vertex = %g %g %g;",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
/* No support in QRT for an arbitrary polygon, we make the
assumption that ths polygon is convex, and split it into
triangles */
COPY_COORD(tvert[0], vert[0]);
for (i=1;i<tot_vert-1;i++) {
COPY_COORD(tvert[1], vert[i]);
COPY_COORD(tvert[2], vert[i+1]);
fprintf(outfile, "TRIANGLE ( ");
fprintf(outfile, "loc = (%g, %g, %g), ",
tvert[0].x, tvert[0].y, tvert[0].z);
fprintf(outfile, "vect1 = (%g, %g, %g), ",
tvert[1].x - tvert[0].x, tvert[1].y - tvert[0].y,
tvert[1].z - tvert[0].z);
fprintf(outfile, "vect2 = (%g, %g, %g) ",
tvert[2].x - tvert[0].x, tvert[2].y - tvert[0].y,
tvert[2].z - tvert[0].z);
fprintf(outfile, " );\n");
}
break;
case OUTPUT_RAYSHADE:
fprintf(outfile, "polygon ");
if (texture_name != NULL)
fprintf(outfile, "%s ", texture_name);
for (num_vert=0;num_vert<tot_vert;num_vert++)
fprintf(outfile, "%g %g %g ",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z);
fprintf(outfile, "\n");
break;
}
}
/*
* Output polygonal patch. A patch is defined by a set of vertices and their
* normals. With these databases, a patch is defined to have all points
* coplanar. A patch has only one side, with the order of the vertices being
* counterclockwise as you face the patch (right-handed coordinate system).
*
* The output format is always:
* "pp" total_vertices
* vert1.x vert1.y vert1.z norm1.x norm1.y norm1.z
* [etc. for total_vertices polygonal patches]
*
*/
void
lib_output_polypatch(tot_vert, vert, norm)
int tot_vert;
COORD4 *vert, *norm;
{
int num_vert;
switch (format) {
case OUTPUT_VIDEO:
lib_output_polygon(tot_vert, vert);
break;
case OUTPUT_NFF:
fprintf(outfile, "pp %d\n", tot_vert);
for (num_vert=0;num_vert<tot_vert;++num_vert) {
fprintf(outfile, "%g %g %g %g %g %g\n",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
}
break;
case OUTPUT_POVRAY:
case OUTPUT_POVRAY_15:
if (tot_vert != 3) {
fprintf(outfile, "Smooth triangles must have 3 vertices\n");
exit(1);
}
fprintf(outfile, "object { smooth_triangle { ");
for (num_vert=0;num_vert<tot_vert;++num_vert)
if (format == OUTPUT_POVRAY)
fprintf(outfile, "<%g %g %g> <%g %g %g> ",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
else {
fprintf(outfile, "<%g, %g, %g>, <%g, %g, %g>",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
if (num_vert < 2)
fprintf(outfile, ",");
fprintf(outfile, " ");
}
fprintf(outfile, "}");
if (texture_name != NULL)
fprintf(outfile, " texture { %s }", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_POLYRAY:
if (tot_vert != 3) {
fprintf(outfile, "Patches must have 3 vertices, input was %d\n",
tot_vert);
exit(1);
}
fprintf(outfile, "object { patch ");
for (num_vert=0;num_vert<tot_vert;++num_vert) {
fprintf(outfile, "<%g, %g, %g>, <%g, %g, %g>",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
if (num_vert<2)
fprintf(outfile, ", ");
}
if (texture_name != NULL)
fprintf(outfile, " %s", texture_name);
fprintf(outfile, " }\n");
break;
case OUTPUT_VIVID:
if (tot_vert != 3) {
fprintf(outfile, "Patches must have 3 vertices, input was %d\n",
tot_vert);
exit(1);
}
fprintf(outfile, "patch = {");
for (num_vert=0;num_vert<tot_vert;++num_vert) {
fprintf(outfile, " vertex = %g %g %g; normal = %g %g %g;",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
}
fprintf(outfile, " }\n");
break;
case OUTPUT_QRT:
/* No smooth patches in QRT, use flat triangles */
lib_output_polygon(tot_vert, vert);
break;
case OUTPUT_RAYSHADE:
if (tot_vert != 3) {
fprintf(outfile, "Smooth triangles must have 3 vertices, not %d\n",
tot_vert);
exit(1);
}
fprintf(outfile, "triangle %d\n", tot_vert);
for (num_vert=0;num_vert<tot_vert;++num_vert) {
fprintf(outfile, "%g %g %g %g %g %g ",
vert[num_vert].x, vert[num_vert].y, vert[num_vert].z,
norm[num_vert].x, norm[num_vert].y, norm[num_vert].z);
}
fprintf(outfile, "\n");
break;
}
}