Skip to content

Instantly share code, notes, and snippets.

@markcmarino
Created February 20, 2020 22:49
Show Gist options
  • Save markcmarino/d97919977181c9efc842238e77f4f6ad to your computer and use it in GitHub Desktop.
Save markcmarino/d97919977181c9efc842238e77f4f6ad to your computer and use it in GitHub Desktop.
Translation of Friedrich Kittler's xsuptrace.c ray tracer code
/*
v. 3.57
31.07.11
PTRACE.PAS (c't 1 / 93,167ff.) Extended
Super ellipsoid, rotational body and procedural textures from povray3
DOS version no longer supported
compile:
Normal: xgraf xsuptrace ray.s matrices.s
// Option -DNEWFRESNEL: simplified Fresnel light from povray3
Option -DJITTER: fuzzy (and time-consuming) shadows
Option -DGAMMA: gamma correction
SVGALIB or DGA: picture.i ".equ XWINDOW, 1" change!
RUNTIME:
<xsuptrace 1>: reproducible noise for runtime tests
FEATURES:
All reflective surfaces can be switched to ReflectionMapping: what
then appears on its surface is a picture to be loaded. This feature
But users have to demand standard interfaces first.
Prompts (':') for scalars and vectors can be defined either with <w [eiter]>
or <n [on]> acknowledge or answer with a new input
3 constant objects: sky, hell, ground (which only allows plein-air images)
Any number of variable objects (limited only by memory)
As variable objects by default 2 balls and 1 other object each predefined
ned. But standard objects can be deleted again.
If more than the standard number is required by an object, inquire
Prompt the new coordinates.
All objects editable (constant only by reassignment of color to normal)
procedure, variable also by location and size).
Some exotic objects are scalable and rotatable. This will be expanded.
Any number of lamps, the first 2 predefined.
Surfaces 1. global, 2. individually assignable after assignment to objects.
LINUX: any size * .24f images can be loaded as 2D textures.
Objects as a ring list for faster intershade () (see Foley, p.
Lamps as a simply linked list.
Left-hand coordinate system: left <x <right, front <y <behind,
below <z <above.
NEW:
01.04.97: AttCol () - acceleration away - transparencies would be worse
07.04.98: individual Fresnel coefficients with individual dullness for
opaque, but metallic surfaces (so these coefficients TransC and
to overwrite the dullness transparently). That's physically correct
and, mirabile dictu, better than POVRAY3. Color charts (ColTabT) global
edierbar
Nov. 22, 1998: ReflV () after Glassner, Image Synthesis, p. 726, again in
Light () calculated per lamp
24.12.98: Object slice selectable; Unzipped DOS - *. 24f files are loadable
08.03.99: Experimental support for Ohta / Maekawa algorithm
01.09.01: DOS no longer supported
13.08.04: Init_Ohta () different, untested
24.10.08: Steel new to /usr/ich/laptop/xsuptrace.c
BUGS:
Spheres of stei, sup, sor determined very empirically
2DMapping on Steiner, Agnesi, SuperQuadrik and Drehkoerper only as a reflection
Map implements: the transformation (x, y, z) -> (u, v) would be hard
MapProc () and Init_Fresnel () are not prepared for multiple calls from xsuptrace
Editing boxes and pyramids still uneven
lambda and thin globally, not variable per surface
No transparency shading as in CALCNEW.C
For floating objects, NULL pointer errors are inevitable; you
Change a midpoint coordinate to small amounts
SOR orb is detected in Edit_Sor () instead of Gravity ()
Refractive indices do not depend on wavelengths of light
08.04.99: intershade () returns L-> Shad correctly, but the object cohesion
breaks again and again, slows down more
30.12.00: xgraf (gcc with optimization) can falsify the SOR curve if
in SorInput the difference quotient Dy / Dx (ie the slope between
two x fixed points) becomes too large.
09.09.03: Changes to transformation matrices only apply to gcc -g. dark
31.07.11: QuColProc () dare
HINTS:
Between internal data structures and user displays, complex conversion
take place; So do not patch global data!
*/
#define SUPTRACE
#define COLTABSIZE 127 // unter DOS ggf. kleiner
#define PIII // bei schlechterer CPU dringend aendern!
// CompileTime: Globale Zaehler, bei neuen Objekten oder Oberflaechen erhoehen
#define SurfCnt 27
#define FormCnt 16
#include <time.h>
#define SPALTEN 640
#define ZEILEN 480
#define RAY
#include "xdefines.h" // SVGALIB: defines.h
#include "ray.h" // SVGALIB: #include bild16m.c || lock16m.c
extern float Infinit,halb,Epsilon;
VCT3 lambda = { 52.36, 56.6, 68.313 };
float duenne = 0.35, LampDiv = 1.;
// RunTime: Zaehler je Sitzung
int ObjCnt = 0;
int RingCnt = 0;
int LampCnt = 0;
int FormCnts[FormCnt] = {0};
int TestFormCnt = FormCnt-1;
#ifdef JITTER
float circle[19][2] = {
{0.75, 0.433}, { 0.0,0.866}, {-0.75,0.433},{-0.75,-0.433 },{0.0,-0.866 },
{0.75,-0.433}, { 0.0,0.0 }, { 0.75,0.0 },{0.375, 0.65 },{-0.375,0.65},
{-0.75,0.0 }, {-0.375,-0.65}, {0.375,-0.65},{0.375,0.216 },{0.0,0.433 },
{-0.375,0.217},{-0.375,-0.216},{0.0,-0.433 },{0.375,-0.217}};
float jitter_offset = 0.75/((float)RAND_MAX);
#endif
// global, um Debuggen und Fehler() zu erlauben
static uint x,y,RDepth = 0;
// global wegen ray.s
VCTd4 dquart;
VCT4 quart;
VCT6 bicub;
#ifdef OHTA
typedef struct { VCT3 dist; float costheta; } dirT;
dirT **direction;
int lastring;
#endif
int normal[FormCnt] = {0,1,4,7,2,11,10,7,6,11,3,14,12,5,2,23};
char ObjStr[FormCnt][32] = {
"den Himmel ",
"die Hoelle ",
"den Boden ",
"eine Kugel ",
"ein Moebiusband ",
"eine Steinerflaeche ",
"einen Torus ",
"ein Ellipsoid ",
"einen Kegel ",
"eine Pyramide ",
"einen Quader ",
"eine Agnesi ",
"ein Superellipsoid ",
"Rotationskoerper ",
"eine Scheibe ",
"eine Lemniskate "
};
FrameT Frame = {
{ 2.0, -8.0, 0.992}, // eye
{ 0.1, 0.1, 0.1 }, // Ambient
0.96, 17, 5,
0.01, 0.0, // AttenEps unbenutzt
{ 0.50, 0.5, 0.6}, 0};// Fog_Color, Fog
LampT *Lampen = NULL;
Prims *Boden,*Hoelle,*Himmel,*Ring,*Last;
int arg = TRUE;
// VORDEFINIERTE OBJEKTE
kugelT k1 = {
{ 2.5, -2.7, 1.0 }, 1.0 };
kugelT k2 = {
{-0.2, -4.0, 1.3 }, 1.15 };
steiT stei = {
{-2.0, -5.0, 1.0},
{ 1.0, 1.0, 1.0}};
moeT moeb = {
{{ 2.4, 0.5, 4.0 }, 1.4 },
0.25, 1 };
torT tor = {
{ 2.9,-5.5, 0.6}, 0.3, 0.1 };
ellT ell = {
{3.8, -3.9, 1.4 },
{0.3, -0.2, 0.6 },
{0,0,0,0,0,0,0,0,0,0}};
coneT cone = {
{{ 1.4,-4.5,1.6 }, 0.29146 },
0.3, 1.4, 0,1,20 };
pyrT pyr = {
{{ 3,4,
{ 1.0, 1.0, 1.0 }, // LINKS - normal
{{-0.9,-1.3, 2.2 }, // links
{ 0.4,-2.5, 2.6 }, // Mitte
{ 0.1,-0.5, 4.2 }}},// oben
{ 3,4,
{ 1.0, 1.0, 1.0 }, // RECHTS
{{ 0.4,-2.5, 2.6 }, // Mitte
{ 1.3, 0.2, 2.2 }, // rechts
{ 0.1,-0.5, 4.2 }}},// oben
{ 3,4,
{ 1.0, 1.0, 1.0 }, // UNTEN
{{ 1.3, 0.2, 2.2 }, // rechts
{ 0.4,-2.5, 2.6 }, // Mitte
{-0.9,-1.3, 2.2 }}}, // links
{ 3,4,
{ 1.0, 1.0, 1.0 }, // HINTEN
{{ 0.1,-0.5, 4.2 }, // oben
{ 1.3, 0.2, 2.2 }, // rechts
{-0.9,-1.3, 2.2 }}}},// links
0, 0 }; // Polygon,dummy
agnT agn = {{{-7.3,0.5,3.5},3.}, {-20, 0, 0}, 1.1 };
BoxInput B1 = { -1,1,3.0,1.5,-1,1 };
boxT box1;
superT sup = {{ -1.5,-1.5,2.4 }, {2.0/0.7,0.7/0.6,2.0/0.6},
{{-1,-1,-1},{1,1,1}},{1,1,1}};
sorInput sorI = {
7,TRUE,
{{ 1.80000,-0.100000},
{ 0.118143,0.020000},
{ 0.620253,0.540084},
{ 0.210970,0.827004},
{ 0.194093,0.962025},
{ 0.286920,1.035000},
{ 0.488354,1.150000}}};
discT scheibe = {{{ -1, 2, 2.7 }, 1.8 }, {0.4,-0.8,0.55}, 1, 0.7 };
lemniT lemnis = {{{ 4.1, -0.8, 1.85 }, 1.3 }, { 90., 0., 0. }};
// Vordefinierte Lampen
LampT L1 = {
{ 4.0, -3.5, 4.5 },
{ 0.95, 0.8, 0.8 },
{ 1.0, 1.0, 1.0 },
0.6, NULL, NULL };
LampT L2 = {
{ -2.0, -3.5, 1.5 },
{ 0.9, 0.9, 1.0 },
{ 1.0, 1.0, 1.0 },
0.3, NULL, NULL };
// TEXTUREN
uchar Lattice[LatCnt][LatCnt][LatCnt];
typedef struct { int Nr; VCT3 c; } ColTabT;
typedef VCT3 ColList[COLTABSIZE+1];
ColList HellTab = {{ 0,0,0 }};
ColList FlameTab = {{ 0,0,0 }};
ColList MarbleTab = {{ 0,0,0 }};
ColTabT MarbleCols[4] = {
{ 0, { 0.41,0.25,0.15}},
{ 36, { 0.20,0.43,0.55}},
{ 66, { 0.91,0.93,0.88}},
{127, { 0.64,0.66,0.55}}};
ColTabT HellCols[4] = {
{ 0, { 0.7, 0.2, 0.1}},
{ 30, { 0.5, 0.8, 0.2}},
{ 60, { 0.9, 0.7, 1.0}},
{127, { 0.7, 0.4, 0.0}}};
ColTabT FlameCols[6] = {
{ 0, { 1.00,1.00,1.00}},
{ 59, { 0.99,0.77,0.42}},
{ 63, { 0.75,0.80,0.51}},
{ 88, { 0.90,0.59,0.34}},
{108, { 0.69,0.38,0.30}},
{127, { 0.12,0.19,0.54}}};
#include "surfaces.h"
float h,v;
/*
#ifdef DEBUG
VCT3 c;
ulong nr_of_rays = 0; // 1199073
ulong nr_of_refl = 0; // 574234
ulong nr_of_refr = 0; // 438160
ulong nr_of_coh = 0; // 66893
ulong nr_of_rest = 0; // 42195
#endif
*/
void
Translate_Object (Prims *Obj, VCT3 *t)
{
TransformT trans;
Compute_Translation_Transform (&trans, t);
Compose_Transforms (&Obj->transform, &trans);
}
void
Scale_Object (Prims *Obj, VCT3 *s)
{
TransformT trans;
Compute_Scaling_Transform (&trans, s);
Compose_Transforms (&Obj->transform, &trans);
}
void
Rotate_Object (Prims *Obj, VCT3 *r)
{
TransformT trans;
Compute_Rotation_Transform (&trans, r);
Compose_Transforms (&Obj->transform, &trans);
}
void
Fehler(void)
{
blau();
printf("%c%s",7,"Nullvektor!\n");
printf("Spalte: %d, Zeile: %d, Tiefe: %d\n",x,y,RDepth);
exit(1);
}
// RAYTRACER-ZUSATZ-FUNKTIONEN
void
FogProc (VCT3 *p,VCT3 *c)
{
float factor;
if ((factor = exp(-vdist(p,&Frame.eye)/Frame.Fog_Distance)) < 0.2)
factor = 0.2;
factor += 0.1 * turbulence(p);
c->x = (c->x - Frame.Fog_Color.x) * factor + Frame.Fog_Color.x;
c->y = (c->y - Frame.Fog_Color.y) * factor + Frame.Fog_Color.y;
c->z = (c->z - Frame.Fog_Color.z) * factor + Frame.Fog_Color.z;
}
void
Gravity(Prims *Obj) // ermittelt Schwerpunkt und von daher Umkugel
{
float r,s,t;
ellT *ep;
torT *tp;
moeT *mp;
coneT *cp;
pyrT *pp;
steiT *sp;
agnT *ap;
boxT *bp;
superT *up;
discT *dp;
lemniT *lp;
int i,j,ganz;
VCT3 d[2];
switch(Obj->form)
{
case moebius:
mp = Obj->UU.moeptr;
r = halb * mp->hoch * mp->hoch * (1 - M_SQRT_2);
Obj->umkugel = mp->ax;
Obj->umkugel.m.x += r;
Obj->umkugel.m.y += r;
Obj->umkugel.rad += mp->hoch * 2;
break;
case steiner:
sp = Obj->UU.steiptr;
Obj->umkugel.m = sp->m;
r = fabs(sp->ax.x);
s = fabs(sp->ax.y);
Obj->umkugel.rad = t = fabs(sp->ax.z);
if (r > s)
{
if (r > t)
Obj->umkugel.rad = r;
}
else
{
if (s > t)
Obj->umkugel.rad = s;
}
break;
case torus:
tp = Obj->UU.torptr;
Obj->umkugel.m = tp->m;
Obj->umkugel.rad = tp->a + tp->b;
tp->a *= tp->a;
tp->b *= tp->b;
break;
case ellipsoid:
ep = Obj->UU.ellptr;
ep->mat.a = r = 1./(ep->ax.x * ep->ax.x);
ep->mat.e = s = 1./(ep->ax.y * ep->ax.y);
ep->mat.h = t = 1./(ep->ax.z * ep->ax.z); // Hyperboloid = -h
ep->mat.d = -ep->m.x*r;
ep->mat.g = -ep->m.y*s;
ep->mat.i = -ep->m.z*t; // Hyperboloid = -i
ep->mat.j = (ep->m.x*ep->m.x*r + ep->m.y*ep->m.y*s
+ ep->m.z*ep->m.z*t)-1;
Obj->umkugel.m = ep->m;
r = fabs(ep->ax.x);
s = fabs(ep->ax.y);
Obj->umkugel.rad = t = fabs(ep->ax.z);
if (r > s)
{
if (r > t)
Obj->umkugel.rad = r;
}
else
{
if (s > t)
Obj->umkugel.rad = s;
}
break;
case kegel:
cp = Obj->UU.coneptr;
r = cp->apex.rad * cp->apex.rad;
Obj->umkugel.m = cp->apex.m;
Obj->umkugel.m.z = halb*(r+1) * (cp->high+cp->low) - r * cp->apex.m.z;
Obj->umkugel.rad = r * (cp->apex.m.z-cp->high) * (cp->apex.m.z-cp->high)
+ (cp->high-Obj->umkugel.m.z) * (cp->high-Obj->umkugel.m.z);
Obj->umkugel.rad = sqrt(Obj->umkugel.rad);
break;
case pyramide:
pp = Obj->UU.pyrptr;
pp->planes = 4;
for (i = 0; i < 4; i++)
{
pp->flaechen[i].vertnum = 3;
pp->flaechen[i].polynum = 4;
}
ganz = pp->flaechen[0].vertnum * pp->planes;
Obj->umkugel.rad = 0;
Obj->umkugel.m.x = Obj->umkugel.m.y = Obj->umkugel.m.z = 0;
for (i = 0; i < pp->planes; i++)
for (j = 0; j < pp->flaechen[i].vertnum; j++)
vaddeq(&Obj->umkugel.m,&pp->flaechen[i].vtx[j]);
vscaleeq(&Obj->umkugel.m,1./(float)ganz);
for (i = 0; i < pp->planes; i++)
for (j = 0; j < pp->flaechen[i].vertnum; j++)
if ((r = vdist(&Obj->umkugel.m,&pp->flaechen[i].vtx[j]))
> Obj->umkugel.rad)
Obj->umkugel.rad = r;
for (i = 0; i < pp->planes; i++)
{
vsub(d,&pp->flaechen[i].vtx[1],&pp->flaechen[i].vtx[0]);
vsub(&d[1],&pp->flaechen[i].vtx[2],&pp->flaechen[i].vtx[1]);
vcross(&pp->flaechen[i].normal,d,&d[1]);
normalize(&pp->flaechen[i].normal);
vsubnorm(d,&pp->flaechen[i].vtx[0],&Obj->umkugel.m);
// gegen falsche Reihenfolge von Polygonecken-Eingaben
negnorm(d,&pp->flaechen[i].normal);
}
break;
case box:
bp = Obj->UU.boxptr;
bp->planes = 6;
for (i = 0; i < 6; i++)
{
bp->flaechen[i].vertnum = 4;
bp->flaechen[i].polynum = 6;
}
ganz = bp->flaechen[0].vertnum * bp->planes;
Obj->umkugel.rad = 0;
Obj->umkugel.m.x = Obj->umkugel.m.y = Obj->umkugel.m.z = 0;
for (i = 0; i < bp->planes; i++)
for (j = 0; j < bp->flaechen[i].vertnum; j++)
vaddeq(&Obj->umkugel.m,&bp->flaechen[i].vtx[j]);
vscaleeq(&Obj->umkugel.m,1./(float)ganz);
for (i = 0; i < bp->planes; i++)
for (j = 0; j < bp->flaechen[i].vertnum; j++)
if ((r = vdist(&Obj->umkugel.m,&bp->flaechen[i].vtx[j]))
> Obj->umkugel.rad)
Obj->umkugel.rad = r;
for (i = 0; i < bp->planes; i++)
{
vsub(d,&bp->flaechen[i].vtx[1],&bp->flaechen[i].vtx[0]);
vsub(&d[1],&bp->flaechen[i].vtx[2],&bp->flaechen[i].vtx[1]);
vcross(&bp->flaechen[i].normal,d,&d[1]);
normalize(&bp->flaechen[i].normal);
vsubnorm(d,&bp->flaechen[i].vtx[0],&Obj->umkugel.m);
// gegen falsche Reihenfolge von Polygonecken-Eingaben
negnorm(d,&bp->flaechen[i].normal);
}
break;
case agnesi:
ap = Obj->UU.agnptr;
Obj->umkugel.m = ap->ax.m;
Obj->umkugel.rad = ap->scale*1.2;
Create_Transform (&Obj->transform);
Rotate_Object (Obj,&ap->rotate);
d[0].x = d[0].y = d[0].z = ap->scale;
Scale_Object(Obj,d);
Translate_Object (Obj,&ap->ax.m);
break;
case super:
up = Obj->UU.supptr;
Obj->umkugel.m = up->m;
if (up->scal.x > up->scal.y)
{
if (up->scal.x > up->scal.z)
Obj->umkugel.rad = up->scal.x;
else
Obj->umkugel.rad = up->scal.z;
}
else
{
if (up->scal.y > up->scal.z)
Obj->umkugel.rad = up->scal.y;
else
Obj->umkugel.rad = up->scal.z;
}
Obj->umkugel.rad *= 1.7; // groesser als theoretisches sqrt(2)
Create_Transform (&Obj->transform);
Scale_Object (Obj,&up->scal);
Translate_Object (Obj, &up->m);
break;
case disc:
dp = Obj->UU.discptr;
Obj->umkugel = dp->ax;
normalize (&dp->normal);
dp->d = -vdot(&dp->ax.m,&dp->normal); // v.Mangold, I,430
break;
case lemni:
lp = Obj->UU.lemniptr;
Obj->umkugel = lp->ax;
Create_Transform (&Obj->transform);
Rotate_Object(Obj,&lp->rotate);
Translate_Object(Obj,&lp->ax.m);
break;
default: ;
}
}
// Spezielle Schnittpunkt-Routinen
#define DEPTH_TOLERANCE 1.0e-3 // double 1.0E-4
#define ZERO_TOLERANCE 1.0e-4 // double 1.0E-10
#define SGNX(x) (((x) >= 0.) ? 1 : -1)
#define MAX_ITERATIONS 20
#define PLANECOUNT 9
static float planes[PLANECOUNT][4] =
{{1, 1, 0, 0}, {1,-1, 0, 0},
{1, 0, 1, 0}, {1, 0,-1, 0},
{0, 1, 1, 0}, {0, 1,-1, 0},
{1, 0, 0, 0}, {0, 1, 0, 0},
{0, 0, 1, 0}};
char
intersect_box (VCT3 *P, VCT3 *D, float *dmin, float *dmax)
{
float tmin,tmax;
// Links/rechts
if (fabs (D->x) > Epsilon)
{
if (D->x > Epsilon)
{
if ((*dmax = (1-P->x) / D->x) < Epsilon)
return FALSE;
*dmin = (-1-P->x) / D->x;
}
else
{
if ((*dmax = (-1-P->x) / D->x) < Epsilon)
return FALSE;
*dmin = (1-P->x) / D->x;
}
if (*dmin > *dmax)
return FALSE;
}
else
{
if (fabs(P->x) > 1)
return FALSE;
*dmin = -Infinit;
*dmax = Infinit;
}
tmin = tmax = 0.;
// Oben/unten
if (fabs (D->y) > Epsilon)
{
if (D->y > Epsilon)
{
tmin = (-1-P->y) / D->y;
tmax = (1-P->y) / D->y;
}
else
{
tmax = (-1-P->y) / D->y;
tmin = (1-P->y) / D->y;
}
if (tmax < *dmax)
{
if (tmax < Epsilon)
return FALSE;
if (tmin > *dmin)
{
if (tmin > tmax)
return FALSE;
*dmin = tmin;
}
else
{
if (*dmin > tmax)
return FALSE;
}
*dmax = tmax;
}
else
{
if (tmin > *dmin)
{
if (tmin > *dmax)
return FALSE;
*dmin = tmin;
}
}
}
else
{
if (fabs(P->y) > 1)
return FALSE;
}
// Vorn/hinten
if (fabs (D->z) > Epsilon)
{
if (D->z > Epsilon)
{
tmin = (-1-P->z) / D->z;
tmax = (1-P->z) / D->z;
}
else
{
tmax = (-1-P->z) / D->z;
tmin = (1-P->z) / D->z;
}
if (tmax < *dmax)
{
if (tmax < Epsilon)
return FALSE;
if (tmin > *dmin)
{
if (tmin > tmax)
return FALSE;
*dmin = tmin;
}
else
{
if (*dmin > tmax)
return FALSE;
}
*dmax = tmax;
}
else
{
if (tmin > *dmin)
{
if (tmin > *dmax)
return FALSE;
*dmin = tmin;
}
}
}
else
{
if (fabs(P->z) > 1)
return FALSE;
}
*dmin = tmin;
*dmax = tmax;
return TRUE;
}
float
intersect_superellipsoid (Prims *Superell,rayT *Ray)
{
int i,cnt;
float t,t1,t2,v0,v1,val,dists[PLANECOUNT+2];
VCT3 P,D,P0,P1,P2,P3;
// Transform the ray into the superellipsoid space
MInvTransPoint (&P, &Ray->p, &Superell->transform);
MInvTransDirection (&D, &Ray->n, &Superell->transform);
if (!intersect_box (&P, &D, &t1, &t2))
return Infinit;
// Test if superellipsoid lies behind the ray origin
if (t2 < DEPTH_TOLERANCE)
return Infinit;
if (t1 < DEPTH_TOLERANCE)
t1 = DEPTH_TOLERANCE;
dists[0] = t1;
dists[1] = t2;
// Intersect ray with planes cutting superellipsoids in pieces
if ((cnt = find_ray_plane_points(&P, &D, dists, t1, t2)) < 2)
return Infinit;
vadds(&P0,&D,&P,dists[0]);
if ((fabs(v0 = eval_super(&P0,&Superell->UU.supptr->Power)))
< ZERO_TOLERANCE)
if ((val = dists[0] ) > DEPTH_TOLERANCE)
return val;
for (i = 1; i < cnt; i++)
{
vadds(&P1,&D,&P,dists[i]);
if ((fabs (v1 = eval_super(&P1,&Superell->UU.supptr->Power)))
< ZERO_TOLERANCE)
{
if ((val = dists[i]) > DEPTH_TOLERANCE)
return val;
}
else
{
if (v0*v1 < 0.)
{
// Opposite signs, there must be a root between
solve_hit1 (&Superell->UU.supptr->Power, v0, &P0, v1, &P1, &P2);
if ((val = vsubnorm (&P3,&P2,&P)) > DEPTH_TOLERANCE)
return val;
}
else
{
/*
Although there was no sign change, we may actually be approaching
the surface. In this case, we are being fooled by the shape of the
surface into thinking there isn't a root between sample points.
*/
if (check_hit2 (&Superell->UU.supptr->Power,&P,&D,dists[i-1],&P0,v0,
dists[i],&t,&P2))
{
if ((val = t) > DEPTH_TOLERANCE)
return val;
else
break;
}
}
}
v0 = v1;
P0 = P1;
}
return Infinit;
}
int
compdists (const void *in_a, const void *in_b)
{
float a,b;
a = *((float *)in_a);
b = *((float *)in_b);
if (a < b)
return -1;
if (a == b)
return 0;
return 1;
}
/*
Find all the points where the ray intersects the set of subdividing planes
through the superquadric. Return the number of valid hits (within the bounding
box).
*/
int
find_ray_plane_points (VCT3 *P, VCT3 *D, float *dists, float mindist,
float maxdist)
{
int i, cnt = 2;
float t, d;
/*
Since min and max dist are the distance to 2 of the bounding planes we are
considering, there is a high probability of missing them due to round off
error. Therefore we adjust min and max.
*/
t = Epsilon * (maxdist - mindist);
mindist -= t;
maxdist += t;
// Check the sets of planes that cut apart the superquadric
for (i = 0; i < PLANECOUNT; i++)
{
if (fabs(d = (D->x * planes[i][0] + D->y * planes[i][1] + D->z
* planes[i][2])) < Epsilon)
// Can't possibly get a hit for this combination of ray and plane
continue;
t = (planes[i][3] - (P->x * planes[i][0] + P->y * planes[i][1]
+ P->z * planes[i][2])) / d;
if ((t >= mindist) && (t <= maxdist))
dists[cnt++] = t;
}
// sort the results for further processing
qsort ((void *)(dists), (size_t)cnt, sizeof(float), compdists);
return cnt;
}
/*
Home in on the root of a superquadric using a combination of secant and bi-
section methods. This routine requires that the sign of the function be diffe-
rent at P0 and P1, else it will fail drastically.
FAK: corrected a severe bug. v3 and v2 were not copied into v0 and v1.
*/
void
solve_hit1 (VCT3 *power, float v0, VCT3 *tP0, float v1, VCT3 *tP1, VCT3 *P)
{
VCT3 P0, P1, P2, P3;
int i;
float x, v2, v3;
P0 = *tP0;
P1 = *tP1;
for (i = 0; i < MAX_ITERATIONS; i++)
{
if (fabs(v0) < ZERO_TOLERANCE)
{
*P = P0; // Near point is close enough to an intersection
return;
}
if (fabs(v1) < ZERO_TOLERANCE)
{
*P = P1; // Far point is close enough to an intersection
return;
}
// The sign of v0 and v1 changes between P0 and P1, this means there is an
// intersection point in there somewhere. Look at the chord connecting P0
// and P1. Assume a line between the points.
x = fabs(v0 / (v1 - v0));
P2.x = (P1.x-P0.x) * x + P0.x;
P2.y = (P1.y-P0.y) * x + P0.y;
P2.z = (P1.z-P0.z) * x + P0.z;
v2 = eval_super (&P2, power);
// Look at the midpoint between P0 and P1
P3.x = halb * (P1.x+P0.x);
P3.y = halb * (P1.y+P0.y);
P3.z = halb * (P1.z+P0.z);
v3 = eval_super (&P3, power);
if (v0 * v2 > 0)
{
if (v0 * v3 > 0)
{
if (x < halb)
{
P0 = P3;
v0 = v3;
}
else
{
P0 = P2;
v0 = v2;
}
}
else
{
// We can move both ends
v0 = v2;
v1 = v3;
P0 = P2;
P1 = P3;
}
}
else
{
if (v0 * v3 > 0)
{
// We can move both ends
v0 = v3;
v1 = v2;
P0 = P3;
P1 = P2;
}
else
{
if (x < halb)
{
v1 = v2;
P1 = P2;
}
else
{
v1 = v3;
P1 = P3;
}
}
}
}
if (i == MAX_ITERATIONS)
{
// The loop never quite closed in on the result - just use the point
// closest to zero. This really shouldn't happen since the max number
// of iterations is enough to converge with straight bisection.
if (fabs(v0) < fabs(v1))
*P = P0;
else
*P = P1;
}
}
// Try to find the root of a superquadric using Newton's method
int
check_hit2 (VCT3 *power, VCT3 *P, VCT3 *D, float t0, VCT3 *P0, float v0,
const float t1, float *t, VCT3 *Q)
{
int i;
float dt0, dt1, v1, deltat, maxdelta;
VCT3 P1;
maxdelta = t1 - t0;
dt0 = t0;
dt1 = t0 + 0.001 * maxdelta;
for (i = 0; (dt0 < t1) && (i < MAX_ITERATIONS); i++)
{
vadds(&P1,D,P,dt1);
v1 = eval_super (&P1,power);
if (v0 * v1 < 0)
{
// Found a crossing point, go back and use normal root solving
solve_hit1 (power, v0, P0, v1, &P1, Q);
*t = vsubnorm (P0,Q,P);
return TRUE;
}
else
{
if (fabs(v1) < ZERO_TOLERANCE)
{
*t = dt1;
return TRUE;
}
else
{
if (((v0 > 0) && (v1 > v0)) || ((v0 < 0) && (v1 < v0)))
break; // We definitely failed
else
{
if (v1 == v0)
break;
else
deltat = v1 * (dt1 - dt0) / (v1 - v0);
}
}
}
if (fabs(deltat) > maxdelta)
break;
v0 = v1;
dt0 = dt1;
dt1 -= deltat;
}
return FALSE;
}
float roots[SOR_POINTS*3];
float
intersect_sor (Prims *Obj, rayT *Ray, float lmin)
{
int i,j,n,flag;
float r0,a,b,c,k,l,u,v;
double x0;
VCTd3 cu;
VCT3 P,D;
SOR_SPLINE_ENTRY *Entry;
sorT *Sor = Obj->UU.sorptr;
MInvTransPoint (&P,&Ray->p,&Obj->transform);
MInvTransDirection (&D,&Ray->n,&Obj->transform);
// Test if ray misses object's bounds
if (((D.y >= 0) && (P.y > Sor->Height2)) ||
((D.y <= 0) && (P.y < Sor->Height1)) ||
((D.x >= 0) && (P.x > Sor->Radius2)) ||
((D.x <= 0) && (P.x < -Sor->Radius2)))
return Infinit;
// Get distance of the ray from rotation axis (= y axis)
r0 = P.x * D.z - P.z * D.x;
if ((a = D.x * D.x + D.z * D.z) > 0)
r0 /= sqrt(a);
// Test if ray misses object's bounds
if (r0 > Sor->Radius2)
return Infinit;
if (fabs(D.y) > Epsilon)
{
// Test base/cap plane
if (Sor->closed)
{
// Test base plane
if (Sor->Base_Radius_Squared > 0)
{
if ((k = (Sor->Height1 - P.y) / D.y) > Epsilon)
{
u = P.x + k * D.x;
v = P.z + k * D.z;
if (u * u + v * v <= Sor->Base_Radius_Squared)
{
Sor->curve = FALSE;
return k;
}
}
}
// Test cap plane
if (Sor->Cap_Radius_Squared > 0)
{
if ((k = (Sor->Height1 - P.y) / D.y) > Epsilon)
{
u = P.x + k * D.x;
v = P.z + k * D.z;
if (u * u + v * v <= Sor->Cap_Radius_Squared)
{
Sor->curve = FALSE;
return k;
}
}
}
}
}
// Test all spline segments
#if 0
if ((roots = calloc (Sor->Number,sizeof(VCT3))) == NULL)
{
blau();
perror("malloc: SOR-Wurzel");
exit(-1);
}
#else
memset (roots,0,sizeof(VCT3)*Sor->Number);
#endif
v = lmin;
flag = -1;
b = P.x * P.x + P.z * P.z;
c = 2 * (P.x * D.x + P.z * D.z);
for (j = 0; j < Sor->Number; j++)
{
Entry = &Sor->Spline->Entry[j];
// Test if ray misses segment's bounds
if (r0 > Entry->r2)
continue;
if (((D.y >= 0) && (P.y > Entry->h2)) ||
((D.y <= 0) && (P.y < Entry->h1)) ||
((D.x >= 0) && (P.x > Entry->r2)) ||
((D.x <= 0) && (P.x < -Entry->r2)))
continue;
// Cubic curve
x0 = 1./(Entry->A * D.y * D.y * D.y);
cu.x = x0 * (D.y * D.y * (3 * Entry->A * P.y + Entry->B) - a);
cu.y = x0 * (D.y * (P.y * (3 * Entry->A * P.y + 2 * Entry->B) + Entry->C)
- c);
cu.z = x0 * (P.y * (P.y * (Entry->A * P.y + Entry->B) + Entry->C) +
Entry->D - b);
n = cubic (&cu, &bicub);
if (((k = bicub.rx) > Epsilon) && ((u = k) < v))
{
if (((l = P.y + k * D.y) > Entry->h1) && (l <= Entry->h2))
{
if (flag < 0)
flag = 3*j;
roots[3*j] = u;
}
}
if (n) // 3 reelle Loesungen
{
if (((k = bicub.ry) > Epsilon) && ((u = k) < v))
{
if (((l = P.y + k * D.y) >= Entry->h1) && (l <= Entry->h2))
{
if (flag < 0)
flag = 3*j+1;
roots[3*j+1] = u;
}
}
if (((k = bicub.rz) > Epsilon) && ((u = k) < v))
{
if (((l = P.y + k * D.y) > Entry->h1) && (l <= Entry->h2))
{
if (flag < 0)
flag = 3*j+2;
roots[3*j+2] = u;
}
}
}
}
if (flag >= 0)
{
for (i = flag; i < 3*j; i++)
{
if ((roots[i] > Epsilon) && (roots[i] < v))
{
v = roots[i]; // kleinste positiv reelle Loesung
Sor->curve = TRUE;
Sor->SplineNr = i/3;
}
}
}
return v;
}
#if 0
static void
nrmSor (VCT3 *IPoint,Prims *Obj,VCT3 *N)
{
sorT *Sor = Obj->UU.sorptr;
SOR_SPLINE_ENTRY *Entry;
// Deckel
if (!Sor->curve)
{
N->x = N->z = 0;
N->y = 1;
}
else
{
MInvTransPoint(N,IPoint,&Obj->transform);
Entry = &Sor->Spline->Entry[Sor->SplineNr];
N->y = -halb * (N->y * (3 * Entry->A * N->y + 2 * Entry->B) + Entry->C);
}
MTransNormalize (N,N,&Obj->transform);
}
static void
nrmSuper (VCT3 *IPoint, Prims *Superell, VCT3 *Nrm)
{
float k,x,y,z;
VCT3 E;
MInvTransPoint (Nrm, IPoint, &Superell->transform);
E = Superell->UU.supptr->Power;
x = fabs(Nrm->x);
y = fabs(Nrm->y);
z = fabs(Nrm->z);
k = pos_power(pos_power(x, E.x) + pos_power(y, E.x), E.y - 1.);
Nrm->x = k * SGNX(Nrm->x) * pos_power(x, E.x - 1.);
Nrm->y = k * SGNX(Nrm->y) * pos_power(y, E.x - 1.);
Nrm->z = SGNX(Nrm->z) * pos_power(z, E.z - 1.);
MTransNormalize (Nrm, Nrm, &Superell->transform);
}
#endif
void
Sor_Radii (sorT *Sor,int i)
{
double A,B,C,D,w;
float r;
// Get cap radius
w = Sor->Spline->Entry[i].h1;
A = Sor->Spline->Entry[i].A;
B = Sor->Spline->Entry[i].B;
C = Sor->Spline->Entry[i].C;
D = Sor->Spline->Entry[i].D;
if ((r = w * (w * (A * w + B) + C) + D) < 0)
Sor->Cap_Radius_Squared = 0;
else
Sor->Cap_Radius_Squared = r; // bei gcc -O Rechenfehler: r = 2*r!
// Get base radius
w = Sor->Spline->Entry[0].h1;
A = Sor->Spline->Entry[0].A;
B = Sor->Spline->Entry[0].B;
C = Sor->Spline->Entry[0].C;
D = Sor->Spline->Entry[0].D;
if ((r = w * (w * (A * w + B) + C) + D) < 0)
Sor->Base_Radius_Squared = 0;
else
Sor->Base_Radius_Squared = r;
}
void // hier scheitert TC
Compute_Sor (sorInput *SorI,Prims *Obj)
{
int i,n;
float A,B,C,D,w,k[4];
float x[4],y[2],r[2];
float xmax,ymax,ymin;
VCT3 c;
MatrixT Mat;
sorT *Sor = Obj->UU.sorptr;
Sor->Number = SorI->Number-3;
Sor->closed = SorI->closed;
Sor->Entry = FormCnts[Obj->form]; // FAK
if ((Sor->Spline = (SOR_SPLINE *)malloc(sizeof(SOR_SPLINE))) == NULL)
{
perror("malloc: SOR-Spline");
exit(-1);
}
if ((Sor->Spline->Entry = (SOR_SPLINE_ENTRY *)malloc(Sor->Number
*sizeof(SOR_SPLINE_ENTRY))) == NULL)
{
perror("malloc: SOR-Splinewerte");
exit(-1);
}
// Calculate the size of the overall bounding cylinder
xmax = ymax = -Infinit;
ymin = Infinit;
// Calculate segments, i.e. cubic patches
for (i = 0; i < Sor->Number; i++)
{
if ((fabs(SorI->P[i+2].y - SorI->P[i].y) < Epsilon) ||
(fabs(SorI->P[i+3].y - SorI->P[i+1].y) < Epsilon))
{
printf("SOR-Punkt nicht monoton\n");
exit (-1);
}
// Use cubic interpolation
k[0] = SorI->P[i+1].x;
k[1] = SorI->P[i+2].x;
k[2] = (SorI->P[i+2].x - SorI->P[i].x) / (SorI->P[i+2].y - SorI->P[i].y);
k[3] = (SorI->P[i+3].x - SorI->P[i+1].x)/(SorI->P[i+3].y - SorI->P[i+1].y);
k[2] *= 2 * k[0];
k[3] *= 2 * k[1];
k[0] *= k[0];
k[1] *= k[1];
for (n = 0; n < 2; n++)
{
w = SorI->P[i+n+1].y;
Mat[n][0] = w * w * w;
Mat[n][1] = w * w;
Mat[n][2] = w;
Mat[n][3] = Mat[n+2][2] = 1;
Mat[n+2][0] = 3 * w * w;
Mat[n+2][1] = 2 * w;
Mat[n+2][3] = 0;
}
MInvers (Mat);
// Calculate coefficients of cubic patch
A = k[0] * Mat[0][0] + k[1] * Mat[0][1] + k[2] * Mat[0][2]
+ k[3] * Mat[0][3];
B = k[0] * Mat[1][0] + k[1] * Mat[1][1] + k[2] * Mat[1][2]
+ k[3] * Mat[1][3];
C = k[0] * Mat[2][0] + k[1] * Mat[2][1] + k[2] * Mat[2][2]
+ k[3] * Mat[2][3];
D = k[0] * Mat[3][0] + k[1] * Mat[3][1] + k[2] * Mat[3][2]
+ k[3] * Mat[3][3];
if (fabs(A) < Epsilon) A = 0.;
if (fabs(B) < Epsilon) B = 0.;
if (fabs(C) < Epsilon) C = 0.;
if (fabs(D) < Epsilon) D = 0.;
Sor->Spline->Entry[i].A = A;
Sor->Spline->Entry[i].B = B;
Sor->Spline->Entry[i].C = C;
Sor->Spline->Entry[i].D = D;
// Get maximum radius^2 in current segment
Sor->Spline->Entry[i].h1 = y[0] = SorI->P[i+1].y;
Sor->Spline->Entry[i].h2 = y[1] = SorI->P[i+2].y;
x[0] = x[2] = SorI->P[i+1].x;
x[1] = x[3] = SorI->P[i+2].x;
c.x = 3 * A;
c.y = 2 * B;
c.z = C;
n = quadratic (&c, r);
while (n--)
if ((r[n] >= y[0]) && (r[n] <= y[1]))
x[n] = sqrt(r[n] * (r[n] * (r[n] * A + B) + C) + D);
// Set current segment's bounding cylinder
Sor->Spline->Entry[i].r2 = max(max(x[0], x[1]), max(x[2], x[3]));
// Keep track of overall bounding cylinder
xmax = max(xmax, Sor->Spline->Entry[i].r2);
ymin = min(ymin, Sor->Spline->Entry[i].h1);
ymax = max(ymax, Sor->Spline->Entry[i].h2);
}
// Set overall bounding cylinder
Sor->Radius2 = xmax;
Sor->Height1 = ymin;
Sor->Height2 = ymax;
Sor_Radii(Sor,Sor->Number-1);
}
static float // a^2 x^2 y + a^2 y z^2 + y + 1 == 0
intersect_agnesi (Prims *A, rayT *ray)
{
VCTd3 in;
double a,b,c,d;
float r;
VCT3 m,n;
agnT *P = A->UU.agnptr;
MInvTransPoint (&m,&ray->p,&A->transform);
MInvTransDirection (&n,&ray->n,&A->transform);
a = P->ax.rad * P->ax.rad;
c = n.x*n.x + n.z*n.z;
b = 1/(a * n.y * c);
d = n.x*m.x + n.z*m.z;
in.x = a*b*(2*n.y * d + m.y * c);
c = m.x*m.x + m.z*m.z;
in.y = (n.y + a * (n.y*c + 2*m.y * d)) * b;
in.z = (m.y * (1 + a*c) + 1) * b;
if (!cubic(&in,&bicub)) // 1 reelle Loesung
{
if (bicub.rx > Epsilon)
return bicub.rx;
}
else // 3 reelle Loesungen
{
if (bicub.rx > bicub.ry) // zuerst sortieren
{
r = bicub.ry; bicub.ry = bicub.rx; bicub.rx = r;
}
if (bicub.ry > bicub.rz)
{
r = bicub.rz; bicub.rz = bicub.ry; bicub.ry = r;
}
if (bicub.rx > Epsilon) // kleinste positive Loesung suchen
return bicub.rx;
if (bicub.ry > Epsilon)
return bicub.ry;
if (bicub.rz > Epsilon)
return bicub.rz;
}
return Infinit;
}
static float // a^4 x^4 - a^2 (x^2 + y^2 + z^2) = 0
intersect_lemni (Prims *A, rayT *ray)
{
VCT3 m,n;
double d,a,a2,mx2,n2;
float ret = Infinit;
uint r;
lemniT *P = A->UU.lemniptr;
MInvTransPoint (&m,&ray->p,&A->transform);
MInvTransDirection (&n,&ray->n,&A->transform);
n2 = n.x * n.x;
a = 1./P->ax.rad;
a2 = a * a;
d = n2 * n2;
mx2 = m.x * m.x;
dquart.x = (a * m.x * n2 * n.x)*4/d;
dquart.y = (6 * n2 * mx2 * a2 + n.y * n.y + n.z * n.z - n2)/d;
dquart.z = 2*a/d*(n.z * m.z + n.y * m.y + m.x * n.x * (2 * mx2 * a2 - 1));
dquart.w = a2/d * (m.z * m.z + m.y * m.y + mx2 * (mx2 * a2 - 1));
if (!(r = quartic(&dquart,&quart)))
return ret;
if (quart.z < quart.w && quart.z > Epsilon)
ret = quart.z;
else if (quart.w > Epsilon)
ret = quart.w;
if (r < 2)
return ret;
if (quart.x < ret && quart.x > Epsilon)
ret = quart.x;
if (quart.y < ret && quart.y > Epsilon)
ret = quart.y;
return ret;
}
// FRESNEL, Watt I, 76ff.
float
getmu (const float f0)
{
float s = sqrt(f0);
if (s >= 1)
return 3996001.0; // s = 0.999
s = (1+s)/(1-s);
return s*s;
}
#ifndef SUPTRACE // von ray.s-fresnel() ersetzt
static void // Watt, 3D Graphics, frei portiert
fresnel (float NdotHn,float LdotN,SurfT *S,VCT3 *Hn,VCT3 *I,VCT3 *N,VCT3 *c)
{
float phi,D,Gs,Gm,G,rs;
float VdotHn,NdotI;
phi = NdotHn * NdotHn;
D = S->transpar * M_1_PI/sqr(phi) * exp((phi-1)/phi * S->transpar);
VdotHn = 2 * NdotHn / vdot (I,Hn);
Gm = LdotN * VdotHn;
NdotI = vdot (N,I);
((Gs = NdotI * VdotHn) < Gm) ? (G = Gs) : (G = Gm);
if (G <= 0)
return;
rs = D / NdotI * LampDiv;
if (G < 1)
rs *= G;
phi = acos (LdotN);
c->x += S->SpecC.x * getfresnel (phi, S->TransC.x) * rs;
c->y += S->SpecC.y * getfresnel (phi, S->TransC.y) * rs;
c->z += S->SpecC.z * getfresnel (phi, S->TransC.z) * rs;
}
#endif
// RAYTRACER-KERN
#ifdef OHTA
static char
check_dir (VCT3 *raydir,int act)
// Test, ob ein von Object(lastring) ausgehender Strahl ueberhaupt
// das Objekt act treffen kann
{
// #ifdef DEBUG
// volatile float costheta;
// #else
float costheta;
// #endif
dirT *d;
// gcc verfaelscht sonst act
d = &direction[lastring][act];
if ((costheta = -raydir->x * d->dist.x - raydir->y * d->dist.y
- raydir->z * d->dist.z) < 0 || costheta > d->costheta)
return FALSE;
return TRUE;
}
static Prims *
x (VCT3 *p, rayT *ray) // liefert *p
{
float l,lmin,opak;
Prims *Return,*Obj = Ring;
int i;
pyrT *py;
boxT *bo;
if (ray->n.z >= 0)
{
if (ray->p.z > 0)
Return = Himmel;
else
Return = Boden;
}
else
{
if (ray->p.z < 0)
Return = Hoelle;
else
Return = Boden;
}
if (Return != Boden || ray->n.z == 0) // Null-Div abfangen
lmin = Infinit;
else
lmin = -ray->p.z/ray->n.z;
do
{
if (Obj->ring != lastring)
if (!check_dir(&ray->n,Obj->ring))
continue;
if ((l = sqrSolve(Obj,ray)) < lmin)
switch (Obj->form)
{
case sphere:
lmin = l;
Return = Obj;
break;
case moebius:
if ((l = moebSolve (Obj->UU.moeptr,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case steiner:
if ((l = steinSolve (Obj->UU.steiptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case torus:
if ((l = torSolve (Obj->UU.torptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case ellipsoid:
if ((l = ellSolve (&Obj->UU.ellptr->mat,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case kegel:
if ((l = coneSolve (Obj->UU.coneptr,ray,&opak,Obj->surfptr,p,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case pyramide:
py = Obj->UU.pyrptr;
for (i = 0; i < py->planes; i++)
{
if ((l = polySolve ((triangleT*)(&py->flaechen[i]),ray,p,lmin,FALSE))
< lmin)
{
py->Polygon = i;
lmin = l;
Return = Obj;
}
}
break;
case box:
bo = Obj->UU.boxptr;
for (i = 0; i < bo->planes; i++)
{
if ((l = polySolve ((rectangleT*)(&bo->flaechen[i]),ray,p,lmin,FALSE))
< lmin)
{
bo->Polygon = i;
lmin = l;
Return = Obj;
}
}
break;
case agnesi:
if ((l = intersect_agnesi (Obj,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case super:
if ((l = intersect_superellipsoid (Obj,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case sor:
if ((l = intersect_sor (Obj,ray,lmin)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case disc:
if ((l = discSolve (Obj,ray,p,lmin)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case lemni:
if ((l = intersect_lemni (Obj,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
default: ;
}
}
while ((Obj = Obj->prev) != Ring);
switch (Return->form)
{
case ground: case sphere: case moebius: case steiner: case torus:
case ellipsoid: case agnesi: case super: case sor: case lemni:
RayToPoint (p,ray,lmin);
default: return Return;
}
}
#endif
Prims *
intersect (VCT3 *p, rayT *ray) // liefert *p
{
float opak,l;
volatile float lmin; // volatile gegen SOR-Normalen-Akne
int i;
Prims *Return,*Obj = Ring;
pyrT *py;
boxT *bo;
if (ray->n.z >= 0)
{
if (ray->p.z > 0)
Return = Himmel;
else
Return = Boden;
}
else
{
if (ray->p.z < 0)
Return = Hoelle;
else
Return = Boden;
}
if (Return != Boden || ray->n.z == 0) // Null-Div abfangen
lmin = Infinit;
else
lmin = -ray->p.z/ray->n.z;
do
{
if ((l = sqrSolve(Obj,ray)) < lmin)
{
#ifdef PIII
_mm_prefetch(Obj->next,_MM_HINT_NTA);
#endif
switch (Obj->form)
{
case sphere:
lmin = l;
Return = Obj;
break;
case moebius:
if ((l = moebSolve (Obj->UU.moeptr,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case steiner:
if ((l = steinSolve (Obj->UU.steiptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case torus:
if ((l = torSolve (Obj->UU.torptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case ellipsoid:
if ((l = ellSolve (&Obj->UU.ellptr->mat,ray,&opak,Obj->surfptr,
FALSE)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case kegel:
if ((l = coneSolve (Obj->UU.coneptr,ray,&opak,Obj->surfptr,p,FALSE))
< lmin)
{
lmin = l;
Return = Obj;
}
break;
case pyramide:
py = Obj->UU.pyrptr;
for (i = 0; i < py->planes; i++)
{
if ((l = polySolve ((triangleT*)(&py->flaechen[i]),ray,p,lmin,
FALSE)) < lmin)
{
py->Polygon = i;
lmin = l;
Return = Obj;
}
}
break;
case box:
bo = Obj->UU.boxptr;
for (i = 0; i < bo->planes; i++)
{
if ((l = polySolve ((rectangleT*)(&bo->flaechen[i]),ray,p,lmin,
FALSE)) < lmin)
{
bo->Polygon = i;
lmin = l;
Return = Obj;
}
}
break;
case agnesi:
if ((l = intersect_agnesi (Obj,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case super:
if ((l = intersect_superellipsoid (Obj,ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case sor:
if ((l = intersect_sor (Obj,ray,lmin)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case disc:
if ((l = discSolve (Obj,ray,p,lmin)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
case lemni:
if ((l = intersect_lemni (Obj, ray)) < lmin)
{
lmin = l;
Return = Obj;
}
break;
default: ;
}
}
}
while ((Obj = Obj->prev) != Ring);
switch (Return->form)
{
case ground: case sphere: case moebius: case steiner: case torus:
case ellipsoid: case agnesi: case super: case sor: case lemni:
RayToPoint (p,ray,lmin);
default: return Return; // fall through
}
}
Prims * // Foley, 784
intershade (LampT *L,rayT *ray,float lmin)
{
float l,opak;
int i,j;
Prims *Obj,*Return;
pyrT *py;
boxT *bo;
char typ,shad;
if (!L->Shad)
{
shad = FALSE;
Obj = Ring;
}
else
{
shad = TRUE;
Obj = L->Shad;
}
if (ray->n.z * ray->p.z >= 0)
Return = NULL;
else
Return = Boden; // nur bei LampV.z < 0 noetig
for (i = 0; i < RingCnt; i++, Obj = Obj->prev)
{
// #ifdef PIII
// _mm_prefetch(Obj->prev,_MM_HINT_NTA);
// #endif
if ((l = sqrSolve(Obj,ray)) >= lmin)
continue;
typ = Obj->surfptr->FarbTyp & TRANSP;
switch (Obj->form)
{
case sphere:
if (!typ)
{
if (!shad)
L->Shad = Obj; // Objektkohaerenz startet
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
break;
case moebius:
if ((l = moebSolve (Obj->UU.moeptr,ray)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case steiner:
if ((l = steinSolve (Obj->UU.steiptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case torus:
if ((l = torSolve (Obj->UU.torptr,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case ellipsoid:
if ((l = ellSolve (&Obj->UU.ellptr->mat,ray,&opak,Obj->surfptr,FALSE))
< lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case kegel:
if ((l = coneSolve (Obj->UU.coneptr,ray,&opak,Obj->surfptr,NULL,FALSE))
< lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case pyramide:
py = Obj->UU.pyrptr;
for (j = 0; j < py->planes; j++)
{
if ((l = polySolve ((triangleT*)(&py->flaechen[j]),ray,NULL,lmin,
typ)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
}
break;
case box:
bo = Obj->UU.boxptr;
for (j = 0; j < bo->planes; j++)
{
if ((l = polySolve ((rectangleT*)(&bo->flaechen[j]),ray,NULL,lmin,
typ)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
}
break;
case agnesi:
if ((l = intersect_agnesi (Obj,ray)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case super:
if ((l = intersect_superellipsoid (Obj,ray)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case sor:
if ((l = intersect_sor (Obj,ray,lmin)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case disc:
if ((l = discSolve (Obj,ray,NULL,lmin)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
case lemni:
if ((l = intersect_lemni (Obj,ray)) < lmin)
{
if (!typ)
{
if (!shad)
L->Shad = Obj;
return Obj;
}
else
{
lmin = l;
Return = Obj;
}
}
break;
default: ;
} // switch
} // i-Loop
if (shad && i)
{
// #ifdef DEBUG
// ++nr_of_rest;
// #endif
L->Shad = NULL; // Objektkohaerenz endet, weil i==0 nicht traf
}
return Return;
}
static void // Kegel mit Kannelur [Saeule]
Kannelur(VCT3 *n,coneT *cone)
{
float w,c;
if ((w = cos (cone->ecken * acos (n->x))) > -halb)
{
c = w*halb;
w = sqrt(1-c*c);
n->x = n->x * w + n->y * c;
n->y = n->y * w - n->x * c;
normalize(n);
}
}
static void
GetNrm (VCT3 *p, VCT3 *n, Prims *Obj)
{
VCT3 m;
float a;
switch (Obj->form)
{
case sphere:
nrmSphere (p,Obj,n); break;
case moebius:
nrmMoeb (p,Obj,n); break;
case steiner:
nrmStein (p,Obj,n); break;
case torus:
nrmTorus (p,Obj,n); break;
case ellipsoid:
nrmEll (p,Obj,n); break;
case kegel:
nrmCone (p,Obj,n);
if (Obj->UU.coneptr->kannelur)
Kannelur(n,Obj->UU.coneptr);
break;
case agnesi:
MInvTransPoint(&m,p,&Obj->transform);
a = Obj->UU.agnptr->ax.rad * Obj->UU.agnptr->ax.rad;
n->x = 2 * a * m.x * m.z;
n->z = 2 * a * m.y * m.z;
n->y = 1 + a * (m.x * m.x + m.z * m.z);
MTransNormalize(n,n,&Obj->transform);
break;
case super:
nrmSuper(p,Obj,n); break;
case sor:
nrmSor (p,Obj,n); break;
case disc:
*n = Obj->UU.discptr->normal; break;
case lemni:
MInvTransPoint(&m,p,&Obj->transform);
a = 1./Obj->UU.lemniptr->ax.rad;
*n = m;
n->x = m.x * (2 * a * a * m.x * m.x - 1);
MTransNormalize(n,n,&Obj->transform);
break;
default: ;
}
}
#ifndef JITTER
static void
Light (VCT3 *p, VCT3 *n, Prims *Obj, VCT3 *vi, VCT3 *c)
{
float w1,w2,spec;
rayT shad __attribute__ ((aligned(16))); // scheitert bis gcc-3.2
VCT3 cd,Hn;
LampT *L;
SurfT *T,*S = Obj->surfptr;
Prims *P;
// #ifdef NEWFRESNEL
// float winkel,F;
// #else
float NdotHn;
// #endif
char typ;
S->ColProc (Obj,p,&cd);
typ = S->FarbTyp;
vscaleeq (&cd,LampDiv); // Fehler bei NEWFRESNEL
for (L = Lampen; L != NULL; L = L->next)
{
if ((w1 = vdot (&L->LightN,n)) > 0) // > L->rad f¸r Spotlights
{
CastToRay (&shad,p,&L->LightN);
spec = 2*w1;
w2 = vi->x * (L->LightN.x - spec*n->x) // ReflV(&vr,n,L->LightN);
+ vi->y * (L->LightN.y - spec*n->y) // w2 = vdot(&vr,vi);
+ vi->z * (L->LightN.z - spec*n->z);
if (!(P = intershade (L,&shad,vdist(p,&L->LightV))))
{ // Objekt im Licht
c->x += (L->LightC.x * w1 + Frame.Ambient.x) * cd.x;
c->y += (L->LightC.y * w1 + Frame.Ambient.y) * cd.y;
c->z += (L->LightC.z * w1 + Frame.Ambient.z) * cd.z;
if (!(typ & FRESNEL))
{
if ((typ & REFLEX) && (w2 > 0))
{
spec = pos_power (w2,S->Oe) * LampDiv;
c->x += spec * S->SpecC.x;
c->y += spec * S->SpecC.y;
c->z += spec * S->SpecC.z;
}
}
else
{
#ifdef NEWFRESNEL
if (w2 > 0)
{
if (w1 > 1)
w1 = 1;
winkel = fabs(acos(w1)) * M_2_PI;
F = 0.014567225/sqr(winkel-1.12)-0.011612903;
Hn.x = L->LightC.x * (1 + (1-F)*(cd.x-1));
Hn.y = L->LightC.y * (1 + (1-F)*(cd.y-1));
Hn.z = L->LightC.z * (1 + (1-F)*(cd.z-1));
spec = pos_power (w2,S->Oe);
c->x += spec * Hn.x;
c->y += spec * Hn.y;
c->z += spec * Hn.z;
}
#else
vadd (&Hn, &L->LightN, vi);
normalize (&Hn);
if ((NdotHn = vdot (&Hn,n)) > 0)
fresnel (NdotHn,w1,S,&Hn,vi,n,c);
#endif
}
}
else // Objekt im Schatten
{
/* #ifdef DEBUG
if (L->Shad != NULL)
++nr_of_coh;
#endif
*/
T = P->surfptr;
c->x += Frame.Ambient.x * cd.x;
c->y += Frame.Ambient.y * cd.y;
c->z += Frame.Ambient.z * cd.z;
if (T->FarbTyp & TRANSP)
{
spec = pos_power(w1,1.5) * LampDiv*T->transpar; // 1.5 statt Ot
c->x += spec * T->TransC.x * L->LightC.x;
c->y += spec * T->TransC.y * L->LightC.y;
c->z += spec * T->TransC.z * L->LightC.z;
if ((T->FarbTyp & REFLEX) & (w2 > 0))
{ // neu, 16.02.97
spec = pos_power(w2,S->Oe) * LampDiv * T->transpar;
c->x += spec * S->SpecC.x * L->LightC.x * T->TransC.x;
c->y += spec * S->SpecC.y * L->LightC.y * T->TransC.y;
c->z += spec * S->SpecC.z * L->LightC.z * T->TransC.z;
}
}
} // Schatten
} // w1 > 0
if (typ & IRIS)
{
w2 = LampDiv * 0.1;
spec = duenne * sqrt (S->N*S->N+w1*w1-1);
 c->x += w2 * (1 - cos (spec*lambda.x));
c->y += w2 * (1 - cos (spec*lambda.y));
c->z += w2 * (1 - cos (spec*lambda.z));
}
}
}
#else
void // Watt/Watt, S. 174
ray_jitter(int raynr,LampT *L,float distance,VCT3 *n_jitter)
{
double theta,radius,mu;
VCT3 ray;
((theta = L->rad/distance) > 1) ? (theta = 1) : (theta < -1) ?
(theta = -1) : theta;
radius = L->rad * sqrt(1-theta*theta);
ray.z = distance - L->rad * theta;
ray.x = radius*(circle[raynr][0]+jitter_offset*rand()/(float)RAND_MAX);
ray.y = radius*(circle[raynr][1]+jitter_offset*rand()/(float)RAND_MAX);
mu = hypot(L->LightN.y,L->LightN.z);
n_jitter->x = mu*ray.x + L->LightN.x*ray.z;
n_jitter->y = L->LightN.y*ray.z + L->LightN.z*ray.y/mu
- L->LightN.x*L->LightN.y*ray.x/mu;
n_jitter->z = L->LightN.z*ray.z - L->LightN.y*ray.y/mu
- L->LightN.x*L->LightN.z*ray.x/mu;
normalize(n_jitter);
}
static void
Light (VCT3 *p, VCT3 *n, Prims *Obj, VCT3 *vi, VCT3 *c)
{
float w1,w2,spec,fraction,dist;
int raynr,blockedray;
VCT3 cd,Hn,vr;
rayT shad __attribute__ ((aligned(16)));
LampT *L;
SurfT *T,*S = Obj->surfptr;
Prims *P,*Q = NULL;
char typ;
#ifdef NEWFRESNEL
float winkel,F;
#else
float NdotHn;
#endif
S->ColProc (Obj,p,&cd);
typ = S->FarbTyp;
for (L = Lampen; L != NULL; L = L->next)
{
if ((w1 = vdot (&L->LightN,n)) > 0)
{
if (!(typ & NOSHAD))
{
dist = vdist(&L->LightV,p);
spec = 2*w1;
w2 = vi->x * (L->LightN.x - spec*n->x)
+ vi->y * (L->LightN.y - spec*n->y)
+ vi->z * (L->LightN.z - spec*n->z);
for (raynr = 0,blockedray = 19; raynr < 19; raynr++)
{
ray_jitter (raynr,L,dist,&shad.n);
CastToRay (&shad,p,&shad.n);
if (!(P = intershade (L,&shad,dist)))
{
blockedray--;
if (raynr == 6)
{
Q = P; // Objekt an Jittermittelpunkt
if (blockedray == 12)
{
blockedray = 0;
break;
}
else if (blockedray == 19)
break;
}
}
}
} // !NOSHAD
if ((blockedray) || (typ & NOSHAD))
{
if (!(typ & NOSHAD))
fraction = (float)(blockedray/19.) * LampDiv;
else
fraction = 1.;
c->x += (L->LightC.x * w1+Frame.Ambient.x) * cd.x * fraction;
c->y += (L->LightC.y * w1+Frame.Ambient.y) * cd.y * fraction;
c->z += (L->LightC.z * w1+Frame.Ambient.z) * cd.z * fraction;
if ((w2 > 0) && (typ & 1))
{
spec = pos_power(w2,S->Oe) * fraction;
c->x += spec * S->SpecC.x;
c->y += spec * S->SpecC.y;
c->z += spec * S->SpecC.z;
}
if (typ & FRESNEL)
{
#ifdef NEWFRESNEL
if (w2 > 0)
{
if (w1 > 1)
w1 = 1;
winkel = fabs(acos(w1)) * M_2_PI;
F = 0.014567225/sqr(winkel-1.12)-0.011612903;
Hn.x = L->LightC.x * (1 + (1-F)*(cd.x-1));
Hn.y = L->LightC.y * (1 + (1-F)*(cd.y-1));
Hn.z = L->LightC.z * (1 + (1-F)*(cd.z-1));
spec = pos_power(w2,S->Oe);
c->x += spec * Hn.x;
c->y += spec * Hn.y;
c->z += spec * Hn.z;
}
#else
vadd (&Hn, &L->LightN, vi);
normalize (&Hn);
if ((NdotHn = vdot (&Hn,n)) > 0)
fresnel (NdotHn,w1,&S->SpecC,&Hn,vi,n,c);
#endif
}
}
if (!(typ & NOSHAD)) // Objekt im Schatten
{
T = Q->surfptr;
c->x += Frame.Ambient.x * cd.x * LampDiv;
c->y += Frame.Ambient.y * cd.y * LampDiv;
c->z += Frame.Ambient.z * cd.z * LampDiv;
if (T->FarbTyp & TRANSP)
{
spec = pos_power(fabs(w1),1.5) * LampDiv; // w1^1.5 statt Ot
// spec = fabs(w1) * LampDiv; Ot == 1
// Koeffizient cd getilgt
c->x += spec * T->TransC.x * L->LightC.x;
c->y += spec * T->TransC.y * L->LightC.y;
c->z += spec * T->TransC.z * L->LightC.z;
}
}
} // w1 > 0
if (typ & IRIS)
{
spec = duenne * sqrt (S->N*S->N+w1*w1-1);
w1 = LampDiv * 0.1;
c->x += w1 * (1 - cos (spec*lambda.x));
c->y += w1 * (1 - cos (spec*lambda.y));
c->z += w1 * (1 - cos (spec*lambda.z));
}
}
}
#endif // JITTER
void
trace (rayT ray,float N1,VCT3 *c)
{
VCT3 ci,cs,p,n,vi;
register Prims *Obj;
register SurfT *S;
char noRefl,toTrans,typ;
if (RDepth > Frame.MaxDepth)
{
c->x = c->y = c->z = 0;
return;
}
// #ifdef DEBUG
// ++nr_of_rays;
// #endif
#ifdef OHTA
if (RDepth && lastring >= 0)
Obj = interref (&p,&ray);
else
Obj = intersect (&p,&ray);
#else
Obj = intersect (&p,&ray);
#endif
S = Obj->surfptr;
if (Obj->form < ground) // sky oder hell
{
S->NrmProc (&ray.n,&ray.n,Obj); // neu gegenueber CALCNEW.C
S->ColProc (Obj,&ray.n,c);
if (Frame.Fog)
{
RayToPoint(&p,&ray,20.);
FogProc (&p,c);
}
return;
}
c->x = c->y = c->z = 0;
vi.x = -ray.n.x; // PTrace vsubnorm (&vi,&Frame.eye,&p);
vi.y = -ray.n.y; // CastToTrans() braucht die Kopie vi
vi.z = -ray.n.z;
switch (Obj->form)
{
case ground:
n.x = n.y = 0;
n.z = 1; break;
case pyramide:
n = Obj->UU.pyrptr->flaechen[Obj->UU.pyrptr->Polygon].normal; break;
case box:
n = Obj->UU.boxptr->flaechen[Obj->UU.boxptr->Polygon].normal; break;
default: GetNrm (&p,&n,Obj);
}
negnorm (&vi,&n);
noRefl = S->NrmProc (&p,&n,Obj);
Light (&p,&n,Obj,&vi,c);
if (Frame.Fog)
FogProc (&p,c);
if (((typ = S->FarbTyp) & REFLEX) && (!noRefl))
{
++RDepth;
// #ifdef DEBUG
// ++nr_of_refl;
// #endif
#ifdef OHTA
if (Obj->form <= ground || Obj->form == sor)
lastring = -1;
else
lastring = Obj->ring;
#endif
CastToRefl (&ray,&n,&p);
if (typ & REFMAP)
{
D2MapProc (Obj,&p,&cs);
trace (ray,1,&ci);
c->x += ci.x * cs.x;
c->y += ci.y * cs.y;
c->z += ci.z * cs.z;
}
else
{
trace (ray,1,&ci);
c->x += ci.x * S->SpecC.x;
c->y += ci.y * S->SpecC.y;
c->z += ci.z * S->SpecC.z;
}
--RDepth;
}
if (typ & TRANSP)
{
if (N1 != 1)
toTrans = CastToTrans (&ray,&n,&vi,&p,N1);
else
toTrans = CastToTrans (&ray,&n,&vi,&p,1/S->N);
#ifdef OHTA
if (Obj->form <= ground || Obj->form == sor)
lastring = -1;
else
lastring = Obj->ring;
#endif
if (toTrans)
{
// #ifdef DEBUG
// ++nr_of_refr;
// #endif
if (typ & HOLLOW)
N1 = 1;
else
(N1 != 1) ? (N1 = 1) : (N1 = S->N);
++RDepth;
trace (ray,N1,&ci);
--RDepth;
c->x += ci.x * S->TransC.x;
c->y += ci.y * S->TransC.y;
c->z += ci.z * S->TransC.z;
}
else if ((!noRefl) && (typ & REFLEX))
{ // Totalreflexion
++RDepth;
// #ifdef DEBUG
// ++nr_of_refl;
// #endif
trace (ray,1,&ci);
--RDepth;
c->x += ci.x * (1 - S->SpecC.x);
c->y += ci.y * (1 - S->SpecC.y);
c->z += ci.z * (1 - S->SpecC.z);
}
}
}
// PROZEDURALE OBERFLAECHEN
void
EqOdProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
*c = Obj->surfptr->Od;
}
void
CloudProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
register float t;
VCT3 v;
*c = Obj->surfptr->Od;
v.x = p->x * 0.03;
v.y = p->y * 0.1;
v.z = p->z * 0.1;
t = turbulence (&v);
c->x *= t;
c->y *= t;
}
void
MarbleProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
VCT3 t;
uint s;
vscale (&t,p,0.4);
if ((s = COLTABSIZE*turbulence(&t)) > COLTABSIZE)
s = COLTABSIZE;
*c = MarbleTab[s];
}
void
HellProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
uint s;
VCT3 t;
t.x = p->x * 0.4;
t.z = p->z * 0.4;
t.y = p->y * 0.24;
if ((s = turbulence(&t)*COLTABSIZE) > COLTABSIZE)
s = COLTABSIZE;
*c = HellTab[s];
}
void
FlameProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
VCT3 t;
int s;
float f;
t = *p;
switch (Obj->form)
{
case sky:
t.z = 4 * (t.z-0.27); break;
case hell:
t.z = t.x+t.y; break;
case ground:
f = 0.3 * t.y + 3;
vscaleeq (&t,0.1);
t.z = f + t.z - 4 * turbulence (&t);
break;
case sphere: case kegel: case torus: case ellipsoid: case pyramide:
case box: case lemni:
vsub (&t,p,&Obj->umkugel.m);
vscaleeq (&t,1./Obj->umkugel.rad);
break;
case moebius:
vsub (&t,p,&Obj->umkugel.m);
vscaleeq (&t,1./Obj->UU.moeptr->hoch);
break;
case steiner:
vsub (&t,p,&Obj->umkugel.m);
vscaleeq (&t,1./Obj->umkugel.rad);
t.z *= 2.;
break;
case agnesi: case sor:
MInvTransPoint (&t,p,&Obj->transform);
f = t.y; t.y = t.z; t.z = f;
break;
case super:
vsub (&t,p,&Obj->UU.supptr->m);
vscaleeq (&t, 12./Obj->umkugel.rad);
t.z -= 7 * turbulence (p);
break;
default: ;
}
vscaleeq (&t,0.2);
f = 0.15 * turbulence (&t);
((s = (int)((0.8+t.z+f)*COLTABSIZE)) > COLTABSIZE) ? (s = COLTABSIZE)
: (s < 0) ? (s = 0) : s;
*c = FlameTab[s];
vscaleeq (c,1.2 + f);
if (Obj->form == ground)
c->z += 0.2;
}
void
WoodProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
char tst = FALSE;
float s,rad,zufall;
VCT3 v,t;
v = *p;
t = *p;
switch (Obj->form)
{
case sphere: case super: case lemni:
vscaleeq (&v,0.1/Obj->umkugel.rad);
vscaleeq (&t,1.2/Obj->umkugel.rad); break;
case kegel:
t.x = 2* t.z * (Obj->UU.coneptr->high-Obj->UU.coneptr->low); break;
case pyramide: case box:
vscaleeq (&t,1.5/Obj->umkugel.rad);
break;
case sor:
MInvTransPoint (&t,p,&Obj->transform);
vscaleeq (&t,4.);
vscale (&v,p,0.1);
break;
default:
vscale (&v,p,0.6);
}
s = t.x * t.x + t.y * t.y + turbulence (&v);
zufall = 1. + (float)rand()/RAND_MAX;
if (Obj->form == pyramide || Obj->form == box)
s += 2*sin (p->x*p->y*p->z);
if (Obj->form == ground)
{
s = PI2 * sin (13*p->x-3*M_PI*((int)(2.3*p->x))+3*M_PI*((int)p->y));
rad = 6.8 * hypot (p->x,p->y) + 19*sin (s + 9*t.y);
if (fmod (rad,13) < 6)
tst = TRUE;
}
else if ((s = fmod (s,1)) > 0.4)
tst = TRUE;
if (tst)
{
*c = Obj->surfptr->Od;
vscaleeq(c,zufall);
}
else
{
c->x = 0.2*zufall;
c->y = c->z = 0.17*zufall;
}
}
void
FourProc (Prims *Obj,VCT3 *p,VCT3 *c)
{
VCT3 t,omega = { 11.3,-9.2,13.1 };
VCT3 koeff = { 0.4, 0.47, 0.3 };
double i2;
int i;
switch (Obj->form)
{
case hell:
vscale(&t,p,8); break;
case sphere:
vscale (&t,p,2); break;
default: vscale (&t,p,halb);
}
*c = Obj->surfptr->Od;
t.x = sin(t.x) + M_PI_2;
t.y = sin(t.y) + M_PI_2;
t.z = sin(t.z) + M_PI_2;
omega.x *= p->x;
omega.y *= p->y;
omega.z *= p->z;
for (i = 1; i < 5; i++)
{
i2 = i * i;
c->x += koeff.x * (cos(i2 * omega.x + t.y));
c->y += koeff.y * (cos(i2 * omega.y - t.z));
c->z += koeff.z * (sin(i2 * omega.z + t.x));
vscaleeq (&koeff,(float)M_SQRT_2);
}
schranke(c);
}
static float brickwidth = 0.69;
static float brickheight = 0.53;
static float brickdepth = 0.44;
void // aus povray3
BrickProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
VCT3 t;
int ibrickx, ibricky, ibrickz;
float mortarheight, mortarwidth, mortardepth,brickmortar = 0.107;
float brickx, bricky, brickz;
float bx, by, bz;
t = *p;
switch (Obj->form)
{
case sky: case hell:
vscaleeq (&t,16.); break;
case ground:
t.x = p->z;
t.y = 2*p->y;
t.z = 2*p->x;
break;
case sphere:
vscaleeq(&t,2*Obj->umkugel.rad); break;
case ellipsoid: case kegel:
vscaleeq(&t,3*Obj->umkugel.rad); break;
case moebius: case pyramide: case box:
vsub(&t,&t,&Obj->umkugel.m);
vscaleeq(&t,Obj->umkugel.rad);
bx = t.x; t.x = t.y; t.y = t.z; t.z = bx;
break;
default: vscaleeq(&t,1./Obj->umkugel.rad);
}
bx = t.x + brickmortar + 0.1;
bz = t.y + brickmortar + 0.1;
by = t.z + brickmortar + 0.1;
mortarwidth = brickmortar/brickwidth;
mortarheight = brickmortar/brickheight;
mortardepth = brickmortar/brickdepth;
brickz = bz / brickdepth;
ibrickz = (int)brickz;
if ((brickz -= (float)ibrickz) < 0)
brickz += 1;
if (brickz <= mortarheight)
goto null;
brickz = (bz / brickdepth) * halb;
ibrickz = (int)brickz;
if ((brickz -= (float)ibrickz) < 0)
brickz += 1;
brickx = (bx / brickwidth);
ibrickx = (int)brickx;
if ((brickx -= (float)ibrickx) < 0)
brickx += 1;
if ((brickx <= mortarwidth) && (brickz <= halb))
goto null;
brickx = (bx / brickwidth) + halb;
ibrickx = (int)brickx;
if ((brickx -= (float)ibrickx) < 0)
brickx += 1;
if ((brickx <= mortarwidth) && (brickz > halb))
goto null;
bricky = (by / brickheight);
ibricky = (int)bricky;
if ((bricky -= (float) ibricky) < 0)
bricky += 1;
if ((bricky <= mortardepth) && (brickz > halb))
goto null;
bricky = (by / brickheight) + halb;
ibricky = (int)bricky;
if ((bricky -= (float)ibricky) < 0)
bricky += 1;
if ((bricky <= mortardepth) && (brickz <= halb))
goto null;
*c = Obj->surfptr->Od;
c->x += 0.2 * turbulence (p);
return;
null:
c->x = c->z = 0.29;
c->y = 0.15 + 0.2 * turbulence (&t);
return;
}
void
ChessProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
VCT3 t;
t.x = p->x + 0.1;
t.y = p->y + 0.1;
t.z = p->z + 0.1;
switch (Obj->form)
{
case sky: case hell:
vscaleeq (&t,4.); break;
case ground:
vscaleeq (&t,1.5); break;
case sphere:
vscaleeq (&t,3*Obj->umkugel.rad); break;
case moebius:
t.z /= 2*Obj->UU.moeptr->hoch; break;
case steiner: case box: case lemni:
vscaleeq (&t,4*Obj->umkugel.rad); break;
case torus:
vscaleeq (&t,8*Obj->umkugel.rad); break;
case kegel:
vscaleeq (&t,M_PI*Obj->umkugel.rad); break;
case sor:
vscaleeq (&t,2.);
default: ;
}
t.x -= floor(t.x*halb) * 2 - 0.1;
t.y -= floor(t.y*halb) * 2 - 0.1;
t.z -= floor(t.z*halb) * 2 - 0.1;
c->y = Obj->surfptr->Od.z;
if (fmod (floor(t.x)+floor(t.y)+floor(t.z),2.) < 1)
{
c->x = Obj->surfptr->Od.x;
c->z = Obj->surfptr->Od.y;
}
else
{
c->x = Obj->surfptr->Od.y;
c->z = Obj->surfptr->Od.x;
}
}
void
QuColProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
VCT3 t;
t = *p;
switch (Obj->form)
{
case sky: case hell:
vscaleeq (&t,2.4); break;
default:
normalize (&t);
}
// vscaleeq (&t,0.05);
t.x *= 0.05;
t.y *= 0.05;
t.z *= 0.05;
*c = Obj->surfptr->Od; // erst hier!
vaddeq (c,&t);
}
void
AgateProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
VCT3 np;
float n;
vscale (&np,p,15.);
if ((n = (sin(np.x) + sin(np.y) + sin(np.z)) / 3. + turbulence (&np)) < 0)
{
*c = MarbleTab[0];
return;
}
else if (n > 1)
n = 1;
*c = MarbleTab[(uint)(pos_power(n,0.77)*COLTABSIZE)];
}
#define sqrt3halb 0.866025404 // sqrt(3)/2
#define sqrt3x3 5.196152423 // sqrt(3)*3
void // aus povray2
HexaProc (Prims *Obj, VCT3 *p, VCT3 *c)
{
int xm,zm,value;
float xs,zs,xl,zl,hz;
VCT3 t;
t = *p;
switch (Obj->form)
{
case sky: case hell:
vscaleeq(&t,8.);
t.y *= 3.;
break;
case ground:
vscaleeq(&t,2.); break;
case sphere:
vsub (&t,p,&Obj->umkugel.m);
vscaleeq(&t,PI2/Obj->umkugel.rad);
t.y = t.z;
break;
case moebius:
t.z /= Obj->UU.moeptr->hoch; break;
case torus:
vscaleeq(&t,8*Obj->umkugel.rad); break;
case steiner: case lemni:
vscaleeq(&t,PI2*Obj->umkugel.rad); break;
case kegel:
vscaleeq(&t,3*M_PI*Obj->umkugel.rad);
t.y *= 2*fabs(Obj->UU.coneptr->high-Obj->UU.coneptr->low);
break;
case ellipsoid:
vscaleeq(&t,M_PI*Obj->umkugel.rad); break;
case pyramide:
vscaleeq (&t,8./Obj->umkugel.rad);
t.y += 4*hypot(p->z,p->x); break;
case box:
vsub (&t,&Obj->umkugel.m,p);
vscaleeq (&t,2.5/Obj->umkugel.rad);
t.y *= hypot(t.x,t.z);
break;
case agnesi: case sor:
vscaleeq(&t,4.);
break;
case super:
vsub (&t,&Obj->umkugel.m,p);
vscaleeq (&t,M_PI);
t.y = t.z;
break;
default: ;
}
hz = t.y < 0 ? sqrt3x3 - fabs(t.y) : t.y;
xs = 2*fabs(t.x);
zs = hz/sqrt3halb;
xs -= floor(xs/6) * 6;
zs -= floor(zs/6) * 6;
xm = (int) floor(xs) % 6;
zm = (int) floor(zs) % 6;
value = 0;
switch (xm)
{
case 0: case 5:
switch (zm)
{
case 0: case 5:
value = 0; break;
case 1: case 2:
value = 1; break;
default:
value = 2;
}
break;
case 2: case 3:
switch (zm)
{
case 0: case 1:
value = 2; break;
case 2: case 3:
value = 0; break;
default:
value = 1;
}
break;
case 1: case 4:
xl = xs-xm;
zl = zs-zm;
if ((xm+zm) % 2)
xl = 1 - xl;
if (!xl)
xl = .0001;
switch ((zl/xl) < 1)
{
case TRUE:
switch (zm)
{
case 0: case 3:
value = 0; break;
case 2: case 5:
value = 1; break;
default:
value = 2;
}
break;
case FALSE:
switch (zm)
{
case 0: case 3:
value = 2; break;
case 2: case 5:
value = 0; break;
default:
value = 1;
}
}
}
switch (value)
{
case 0:
c->x = c->y = Obj->surfptr->Od.x;
c->z = 0; break;
case 1:
c->x = 0;
c->y = c->z = Obj->surfptr->Od.y; break;
default:
c->y = 0;
c->x = c->z = Obj->surfptr->Od.z;
}
}
void
D2SubProc(VCT3 *p,VCT3 *d1,float *u,float *v,char typ)
{
VCT3 d2;
vsubnorm (&d2,p,&Frame.eye);
ReflV (&d2,d1,&d2);
if (typ == 'H')
{
*u = M_PI_2 + halb*atan2(d2.x,d2.z);
*v = M_PI_4 + M_PI_4*d2.y;
}
else
{
*u = M_PI_2 + halb*atan2(d2.x,d2.y);
*v = M_PI_4 + M_PI_4*d2.z;
}
}
void
D2MapProc(Prims *Obj,VCT3 *p,VCT3 *c)
{
VCT3 d1,d2;
int ml;
float winkel,u,v,mr,ro,gr,bl;
SurfT *S = Obj->surfptr;
coneT *cp;
pyrT *pp;
boxT *bp;
char typ;
typ = S->text->typ;
switch(Obj->form)
{
case sky: case hell:
u = p->x/p->z;
v = p->y/p->z;
if (typ != 'V')
{ ro = u; u = v; v = ro; }
break;
case ground:
u = p->x-Frame.eye.x;
v = p->y-Frame.eye.y;
if (typ != 'H')
{ ro = u; u = v; v = ro; }
break;
case sphere:
mr = Obj->umkugel.rad;
nrmSphere(p,Obj,&d1);
v = -d1.x;
if (typ != 'V')
u = -d1.z;
else
u = -d1.y;
(u > 1) ? (u = 1) : (u < -1) ? (u = -1) : u;
u = (M_PI_2+asin(u))*mr;
(v > 1) ? (v = 1) : (v < -1) ? (v = -1) : v;
v = acos(v)*mr;
break;
case moebius: // 2 sin(u)^2 = 1 - dx/hypot(dx,dy)
vsub(&d1,p,&Obj->UU.moeptr->ax.m);
mr = halb * d1.x / hypot(d1.x,d1.y);
if (mr < halb)
u = halb - mr;
else
u = halb + mr;
u = sqrt(u);
v = d1.z/u;
(u > 1) ? (u = 1) : (u < -1) ? (u = -1) : u;
u = asin(u);
if (typ == 'V')
{
mr = u; u = v; v = mr;
}
break;
case steiner:
nrmStein(p,Obj,&d1);
D2SubProc(p,&d1,&u,&v,typ);
break;
case torus:
vsub(&d1,p,&Obj->UU.torptr->m);
u = d1.z/sqrt(Obj->UU.torptr->b);
(u > 1) ? (u = 1) : (u < -1) ? (u = -1) : u;
mr = sqrt(Obj->UU.torptr->a) + sqrt(Obj->UU.torptr->b*(1-u*u));
if (typ == 'V')
{
v = d1.x/mr;
(v > 1) ? (v = 1) : (v < -1) ? (v = -1) : v;
v = acos(v);
}
else
{
v = d1.y/mr;
(v > 1) ? (v = 1) : (v < -1) ? (v = -1) : v;
v = asin(v);
}
break;
case ellipsoid:
nrmEll(p,Obj,&d1);
u = -d1.x;
if (typ != 'V')
v = -d1.y;
else
v = -d1.z;
(u > 1) ? (u = 1) : (u < -1) ? (u = -1) : u;
u = (M_PI_2+asin(u))*ell.ax.x;
(v > 1) ? (v = 1) : (v < -1) ? (v = -1) : v;
if (typ != 'V')
v = acos(v)*ell.ax.y;
else
v = acos(v)*ell.ax.z;
break;
case kegel: // Glassner, Raytracing, 76
cp = Obj->UU.coneptr;
gr = p->x - cp->apex.m.x;
bl = p->z - cp->apex.m.z;
ro = cp->high - cp->low;
v = cp->apex.rad * (cp->apex.m.z - cp->high);
u = cp->apex.rad * (cp->apex.m.z - cp->low);
mr = gr/(u + (v-u) * bl/ro);
(mr > 1) ? (mr = 1) : (mr < -1) ? (mr = -1) : mr;
u = M_PI-acos(mr);
v = bl/ro*M_PI;
if (typ != 'H')
{ ro = u; u = v; v = ro; }
break;
case pyramide:
pp = Obj->UU.pyrptr;
ml = pp->Polygon;
mr = vsubnorm(&d2,&pp->flaechen[ml].vtx[1],&pp->flaechen[ml].vtx[0]);
mr = vsubnorm(&d1,p,&pp->flaechen[ml].vtx[0]);
if ((winkel = fabs(vdot(&d1,&d2))) > 1)
winkel = 1;
v = mr*winkel;
u = mr*sqrt(1-winkel*winkel);
if (typ != 'H')
{ ro = u; u = v; v = ro; }
break;
case box:
bp = Obj->UU.boxptr;
ml = bp->Polygon;
mr = vsubnorm(&d2,&bp->flaechen[ml].vtx[1],&bp->flaechen[ml].vtx[0]);
mr = vsubnorm(&d1,p,&bp->flaechen[ml].vtx[0]);
if ((winkel = fabs(vdot(&d1,&d2))) > 1)
winkel = 1;
v = mr*winkel;
u = mr*sqrt(1-winkel*winkel);
if (typ != 'H')
{ ro = u; u = v; v = ro; }
break;
case agnesi:
MInvTransPoint(&d1,p,&Obj->transform);
ro = Obj->UU.agnptr->ax.rad * Obj->UU.agnptr->ax.rad;
d2.x = 2 * ro * d1.x * d1.y;
d2.z = 2 * ro * d1.z * d1.y;
d2.y = 1 + ro * (d1.x * d1.x + d1.z * d1.z);
MTransNormalize (&d2,&d2,&Obj->transform);
D2SubProc(p,&d2,&u,&v,typ);
break;
case super:
nrmSuper (p,Obj,&d2);
D2SubProc (p,&d2,&u,&v,typ);
break;
case sor:
nrmSor (p,Obj,&d2);
D2SubProc (p,&d2,&u,&v,typ);
break;
case disc:
vsub (&d1,p,&Obj->umkugel.m);
u = d1.x * acos(Obj->UU.discptr->normal.x);
if (typ == 'H')
v = d1.y * asin(Obj->UU.discptr->normal.y);
else
v = d1.z * asin(Obj->UU.discptr->normal.z);
break;
case lemni:
MInvTransPoint(&d1,p,&Obj->transform);
ro = 1./Obj->UU.lemniptr->ax.rad;
d2.x = d1.x * (2 * ro * ro * d1.x * d1.x - 1);
d2.y = d1.y;
d2.z = d1.z;
MTransNormalize (&d2,&d2,&Obj->transform);
D2SubProc(p,&d2,&u,&v,typ);
break;
default: // hier weitere Formen
*c = S->Od;
return; // Unbekanntes abfangen
}
MapProc(S,u,v,c);
}
// NORMALEN-Prozeduren
char
SandProc (VCT3 *p, VCT3 *n, Prims *Obj)
{
VCT3 t,s,nn;
char ret;
nn = *n;
if (Obj->form < ground)
{
n->x += turbulence (&nn);
vscale (&s,n,200.);
}
else
vscale (&s,p,halb);
WaveProc (&s,&nn,Obj);
vscaleeq (&s,0.6);
vscale (&t,p,20.);
RainProc (&t,&nn,Obj);
vscaleeq (&t,0.2);
vaddeq (&s,&t);
*n = nn;
if (dottest (&s,n))
ret = TRUE;
else
ret = FALSE;
if (Obj->form < ground)
{
vaddeq (n,&s);
normalize (n);
}
return ret;
}
#define INV_SQRT_3_4 1.154700538
#ifdef __GNUC__
float quilt_cubic (float t, float c0, float c1) __attribute__ ((const));
#endif
float
quilt_cubic (const float t, const float c0, const float c1)
{
float it = (1-t);
float tsqrd = t*t;
float tcubed = t*tsqrd;
return (tcubed + 3.*t*it*it * c0 + 3.*tsqrd*it * c1) * INV_SQRT_3_4;
}
char // aus povray3
QuiltProc (VCT3 *p, VCT3 *n, Prims *Obj)
{
VCT3 v;
char ret;
switch (Obj->form)
{
case sky: case hell:
vscale (&v,n,2.); break;
case ground:
v = *p; vneg (&v); break;
case sphere: case moebius: case steiner: case lemni:
vsub (&v,p,&Obj->umkugel.m); break;
case torus:
vsub (&v,p,&Obj->UU.torptr->m);
vscaleeq (&v,6*sqrt(Obj->UU.torptr->a));
break;
case ellipsoid:
vsub(&v,p,&Obj->umkugel.m);
vscale (&v,p,1./Obj->umkugel.rad); break;
case kegel: case super:
vsub (&v,p,&Obj->umkugel.m);
vscaleeq(&v,2.);
break;
case pyramide: case box:
vsub (&v,p,&Obj->umkugel.m);
vscaleeq (&v,5.);
break;
default:
v = *p;
}
vscaleeq (&v,2.);
v.x -= floor(v.x) + halb;
v.y -= floor(v.y) + halb;
v.z -= floor(v.z) + halb;
vscaleeq (&v,quilt_cubic(vlength(&v),0.4,0.7));
vaddeq (&v,n);
ret = dottest (&v,n);
*n = v;
normalize (n);
return ret;
}
void
ColQuilt (Prims *Obj, VCT3 *p, VCT3 *c)
{
VCT3 v;
v = *p;
vscaleeq(&v,M_PI);
*c = Obj->surfptr->SpecC;
v.x -= floor(v.x) + halb;
v.y -= floor(v.y) + halb;
v.z -= floor(v.z) + halb;
vscaleeq(&v,quilt_cubic(vlength(&v),.4,.3));
normalize(&v);
vaddeq(c,&v);
schranke(c);
}
char
EqNrmProc (VCT3 *p,VCT3 *n, Prims *Obj)
{
return FALSE;
}
// PROZEDURALE MAPPINGS
void
GenColTab (int SampleCnt, ColList List, ColTabT Cols[])
{
VCT3 co,dif;
int i,j,k;
for (i = 0; i < SampleCnt; i++)
{
if ((k = Cols[i+1].Nr - Cols[i].Nr-1) > 0)
{
co = Cols[i].c;
vsub (&dif,&Cols[i+1].c,&co);
vscaleeq (&dif,1./(float)k);
for (j = Cols[i].Nr; j <= Cols[i+1].Nr; j++)
{
List[j] = co;
vaddeq (&co,&dif);
schranke (&co);
}
}
}
}
// INITIALISIERUNG
// 0. Hilfsfunktionen
#define COLOUR 0x4
void
Print_Vector (char *text, VCT3 *v, int new)
{
char x,y,z;
int n = new;
if (n & COLOUR)
x = 'R', y = 'G', z = 'B';
else
x = 'x', y = 'y', z = 'z';
n &= (COLOUR-1);
if (n)
printf("%s [%c%c%c] : ",text,x,y,z);
else
printf("%s [ %c = % 1.2f, %c = % 1.2f, %c = % 1.2f ] : ",
text,x,v->x,y,v->y,z,v->z);
}
void
Get_Vector (VCT3 *v)
{
char zahl[32];
scanf ("%31s",zahl);
if (*zahl == 'w' || *zahl == 'n')
return;
v->x = (float)strtod (zahl,NULL);
scanf ("%31s",zahl);
v->y = (float)strtod (zahl,NULL);
scanf ("%31s",zahl);
v->z = (float)strtod (zahl,NULL);
}
void
Get_VCT2 (VCT2 *v)
{
char zahl[32];
scanf ("%31s",zahl);
if (*zahl == 'w' || *zahl == 'n')
return;
v->x = (float)strtod (zahl,NULL);
scanf ("%31s",zahl);
v->y = (float)strtod (zahl,NULL);
}
void
Get_Float (float *new)
{
char zahl[32];
scanf ("%31s",zahl);
if (*zahl == 'w' || *zahl == 'n')
return;
*new = (float)strtod (zahl,NULL);
}
void
Print_Float (char *text, float f, int new)
{
if (new)
printf("%s : ",text);
else
printf("%s [% 1.2f] : ",text,f);
}
// 1. Texturen
void
loadmap(Textur *T,FILE *map)
{
ulong mass = BPP;
if (BPP == 4)
--mass;
if (!(T->map = malloc(mass * T->x * T->y)))
{
perror("malloc");
exit(-1);
}
fread(T->map,T->x,mass*T->y,map);
}
void
loadtexture(Prims *Act)
{
FILE *map;
int res = 1;
short bx,by,modus;
char *last,name[32],kurz[32],ext[8] = EXT;
Prims *Obj;
Textur *T;
char name1[64] = "gunzip ";
char name2[64] = "gzip ";
char zipped = FALSE;
printf("Bilddateiname [ohne %s]: ",EXT);
scanf("%31s",name);
Obj = Himmel;
T = Act->surfptr->text;
strtok(name,".");
if (T != NULL)
{
if (!strcmp(name,T->name))
goto info; // Objekt und D2Map schon gekoppelt
else
{
if (T->map)
{
free((void *)(T->map));
T->map = NULL;
}
}
free(T);
T = NULL;
}
if ((T = malloc(sizeof(Textur))) == NULL)
{
perror("malloc");
exit(-1);
}
while (Obj != NULL)
{
if (Obj->surfptr->text != NULL)
{
if (!(res = strcmp(name,Obj->surfptr->text->name)))
{
T = Obj->surfptr->text; // D2Map kopieren
break;
}
}
Obj = Obj->next;
}
if (res) // neue D2Map laden
{
strncpy(kurz,name,10);
if (strncmp(name,theDOS,strlen(theDOS)))
{
zipped = TRUE;
strcat(name,strcat(ext,".gz"));
if (system(strcat(name1,name)) == -1) // "gunzip name.24f.gz"
{
perror("gunzip");
exit(-1);
}
strtok(ext,".gz");
}
strncpy(name,kurz,10);
if ((map = fopen(strcat(name,ext),"rb")) == NULL)
{
perror("fopen");
exit(-1);
}
fread(&bx,sizeof(bx),1,map);
fread(&by,sizeof(by),1,map);
fread(&modus,sizeof(modus),1,map);
if (bx <= 0 || by <= 0)
{
perror("image file void\n");
exit(-1);
}
if (bx > SPALTEN)
bx = SPALTEN;
if (by > ZEILEN)
by = ZEILEN;
T->x = bx; T->y = by;
if ((last = strrchr(name,'/')) != NULL)
{
strtok(name,EXT);
// fuehrendes '/' bzw. '\' weg
strncpy(T->name,last+1,10);
}
else
strncpy(T->name,kurz,10);
loadmap(T,map);
fclose(map);
if (zipped)
system(strcat(name2,name));
}
info:
printf("Streckung [>=1]: ");
Get_Float(&T->big);
if (T->big < 1)
T->big = 1;
printf("Projektion [h/v]: ");
scanf("%3s",kurz);
T->typ = toupper(*kurz);
Act->surfptr->text = T;
}
// 2. Rahmen
void
Edit_Frame (void)
{
float hilf;
char usr[4];
Print_Vector ("Augenpunkt ",&Frame.eye,FALSE);
Get_Vector (&Frame.eye);
Print_Vector ("Umgebungsfarbe ",&Frame.Ambient,FALSE | COLOUR);
Get_Vector (&Frame.Ambient);
printf ("Aspekt [%1.2f] : ",Frame.Aspect);
Get_Float (&Frame.Aspect);
printf ("Bildgroesse [%hd] : ",Frame.PicSizeWC);
hilf = (float)Frame.PicSizeWC;
Get_Float (&hilf);
Frame.PicSizeWC = hilf;
printf ("Rekursionstiefe [%2hd] : ",Frame.MaxDepth);
hilf = (float)Frame.MaxDepth;
Get_Float (&hilf);
Frame.MaxDepth = hilf;
printf ("Nebel [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j' || *usr == 'J')
{
printf("Daempfung [%2.1f <10] : ",Frame.Fog_Distance);
Frame.Fog = TRUE;
Get_Float (&Frame.Fog_Distance);
if ((Frame.Fog_Distance = fabs(Frame.Fog_Distance)) > 10.)
Frame.Fog_Distance = 10.;
Print_Vector("Nebelfarbe ",&Frame.Fog_Color,FALSE | COLOUR);
Get_Vector (&Frame.Fog_Color);
}
}
// 3. Oberflaechen
void
Init_Fresnel (void)
{
Prims *Obj = Himmel;
SurfT *S;
while (Obj)
{
S = Obj->surfptr;
if (S->FarbTyp & FRESNEL)
{
S->TransC.x = getmu(S->TransC.x);
S->TransC.y = getmu(S->TransC.y);
S->TransC.z = getmu(S->TransC.z);
S->transpar = 1./(S->transpar*S->transpar);
}
Obj = Obj->next;
}
}
void
Edit_ColTab (ColTabT L[], int cnt)
{
int i;
float f;
for (i = 0; i < cnt; i++)
{
printf("Stufe = %0.3f",L[i].Nr/(float)COLTABSIZE);
Print_Vector(" ",&L[i].c,COLOUR);
printf("\n");
}
for (i = 0; i < cnt; i++)
{
f = L[i].Nr/(float)COLTABSIZE;
printf("Stufe %1d [%0.3f]: ",i,f);
Get_Float(&f);
if ((!i) && (f != 0))
f = 0;
if (f > 1.)
f = 1.;
L[i].Nr = fabs(f)*(float)COLTABSIZE;
Print_Vector("RGB ",&L[i].c,COLOUR);
Get_Vector(&L[i].c);
}
}
void
Edit_Surface (int Nr, Prims *Act)
{
float val = 0.;
char usr[4],flag = 0;
int typ,farbtyp,cnt = 0;
SurfT *S;
ColTabT *ColT = NULL;
if (Act == NULL)
{
S = SurfList[Nr];
printf("%s\n",SurfStr[Nr]);
}
else
S = Act->surfptr;
usr[1] = '\0';
typ = S->FarbTyp;
again:
printf ("Farbtyp: [%hd] ",S->FarbTyp);
if (!S->FarbTyp)
printf("opak");
else
{
if (S->FarbTyp & REFLEX)
printf("spiegelnd ");
if (S->FarbTyp & TRANSP)
printf("transparent ");
if (S->FarbTyp & IRIS)
printf("Iris ");
if (S->FarbTyp & FRESNEL)
printf("Fresnel ");
if (S->FarbTyp & REFMAP)
printf("Spiegelmapping ");
if (S->FarbTyp & HOLLOW)
printf("hohl ");
if (S->FarbTyp & NOSHAD)
printf("schattenlos ");
}
if (!flag)
{
printf ("\nAnderer Farbtyp? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
{
printf(" 0: opak, 1: spiegelnd, 2: transparent, 4: Iris, 8: Fresnel\n");
printf("16: Spiegelabbildung, 32: hohl, 64: schattenlos\n");
printf("Alle Einzelwerte werden ORiert\n");
Get_Float (&val);
if (((farbtyp = val) & IRIS) || (farbtyp & HOLLOW))
farbtyp |= TRANSP;
if ((farbtyp & FRESNEL) || (farbtyp & REFMAP))
farbtyp |= REFLEX;
if ((farbtyp & FRESNEL) && (farbtyp & TRANSP))
{
farbtyp ^= TRANSP;
printf("Fresnel schliesst Transparenz aus; Transparenz revoziert\n");
}
if (farbtyp != S->FarbTyp)
{
++flag;
S->FarbTyp = farbtyp;
goto again;
}
}
}
printf("\n");
if (S->FarbTyp & REFMAP && (!(typ & REFMAP)))
{
S->ColProc = D2MapProc; // globale Oberflaeche
if (Act != NULL) // Einzeloberflaeche
loadtexture(Act);
}
Print_Vector ("RGB diffus ",&S->Od,FALSE | COLOUR);
Get_Vector (&S->Od);
if (S->FarbTyp & REFLEX)
{
Print_Vector ("RGB spekulaer ",&S->SpecC,FALSE | COLOUR);
Get_Vector (&S->SpecC);
printf ("Phong-Potenz [%2.3f] : ",S->Oe);
Get_Float (&S->Oe);
}
if (S->FarbTyp & TRANSP)
{
Print_Vector ("RGB transparent ",&S->TransC,FALSE | COLOUR);
Get_Vector (&S->TransC);
printf ("Brechungsfaktor [1.0 < %2.3f] : ",S->N);
Get_Float (&S->N);
printf ("Transparenz [0.0 < %0.2f < 1.0] : ",S->transpar);
Get_Float (&S->transpar);
}
if (S->FarbTyp & FRESNEL)
{
Print_Vector ("Fresnel-Refraktion",&S->TransC,FALSE | COLOUR);
Get_Vector (&S->TransC);
printf ("Fresnel-Mattheit [0 < %1.2f < 1] : ",S->transpar);
Get_Float (&S->transpar); // keine Beschraenkung noetig
}
if (S->FarbTyp & IRIS)
{
Print_Vector ("Globale Iris-RGB-Werte ",&lambda,FALSE | COLOUR);
Get_Vector (&lambda);
printf ("Duenne [%2.2f] : ",duenne);
Get_Float (&duenne);
}
// bei neuen Texturen erweitern!
if (Nr == 1 || Nr == 3 || Nr == 8)
{
printf("Farbtafel edieren? [j/n] :");
scanf("%2s",usr);
if (*usr == 'j')
{
switch(Nr)
{
case 1:
ColT = &HellCols[0]; cnt = 4; break;
case 3:
ColT = &MarbleCols[0]; cnt = 4; break;
case 8:
ColT = &FlameCols[0]; cnt = 6; break;
default: return;
}
Edit_ColTab(ColT,cnt);
}
}
}
// 4. Objekte
void
Edit_Kugel (Prims *Act, int new)
{
Print_Vector("Mittelpunkt",&Act->umkugel.m,new);
Get_Vector (&Act->umkugel.m);
Print_Float ("Radius ",Act->umkugel.rad,new);
Get_Float (&Act->umkugel.rad);
}
void
Edit_Moebius (Prims *Act, int new)
{
moeT *m = Act->UU.moeptr;
Print_Vector("Mittelpunkt",&m->ax.m,new);
Get_Vector (&m->ax.m);
Print_Float ("Radius ",m->ax.rad,new);
Get_Float(&m->ax.rad);
Print_Float ("Hoehe ",m->hoch,new);
Get_Float (&m->hoch);
}
void
Edit_Steiner (Prims *Act, int new)
{
steiT *s = Act->UU.steiptr;
Print_Vector("Mittelpunkt",&s->m,new);
Get_Vector (&s->m);
Print_Vector("Achsen ",&s->ax,new);
Get_Vector (&s->ax);
}
void
Edit_Torus (Prims *Act, int new)
{
torT *t = Act->UU.torptr;
Print_Vector("Mittelpunkt ",&t->m,new);
Get_Vector (&t->m);
Print_Float ("Grosser Radius",sqrt(t->a),new);
Get_Float (&t->a);
t->a *= t->a;
Print_Float ("Kleiner Radius",sqrt(t->b),new);
Get_Float (&t->b);
t->b *= t->b;
}
void
Edit_Ellipsoid (Prims *Act, int new)
{
ellT *e = Act->UU.ellptr;
Print_Vector("Mittelpunkt",&e->m,new);
Get_Vector (&e->m);
Print_Vector("Achsen ",&e->ax,new);
Get_Vector (&e->ax);
}
void
Edit_Kegel (Prims *Act, int new)
{
char usr[3] = "x";
float ecken;
coneT *k = Act->UU.coneptr;
Print_Vector("Scheitelpunkt",&k->apex.m,new);
Get_Vector (&k->apex.m);
if (new)
{
printf("Winkel [0.01 < Grad < 85.] : ");
k->apex.rad = 20.;
}
else
printf("Winkel [0.01 < %1.2f < 85.] : ",
180/M_PI*atan(k->apex.rad));
ecken = k->apex.rad;
Get_Float (&k->apex.rad);
if (ecken != k->apex.rad)
{
if (k->apex.rad < 0.01)
k->apex.rad = 0.01;
else if (k->apex.rad > 85.)
k->apex.rad = 85.;
k->apex.rad = tan(GRAD*k->apex.rad);
}
if (new)
printf("Obere Grenze [gemeinhin < Scheitelpunkt.z] : ");
else
printf("Obere Grenze [gemeinhin %1.2f < Scheitelpunkt.z [%1.2f]] : ",
k->high,k->apex.m.z);
Get_Float (&k->high);
Print_Float ("Untere Grenze",k->low,new);
Get_Float (&k->low);
printf("Kannelur? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
{
if (new || k->kannelur == FALSE)
printf("Zahl der Kanneluren : ");
else
printf("Zahl der Kanneluren? [%u] : ",k->ecken);
k->kannelur = TRUE;
Get_Float (&ecken);
k->ecken = (uint)ecken;
}
else
k->kannelur = FALSE;
}
void
Edit_Agnesi (Prims *Act, int new)
{
agnT *k = Act->UU.agnptr;
Print_Vector ("Mittelpunkt ",&k->ax.m,new);
Get_Vector (&k->ax.m);
if (new)
printf ("Steigung [>1.0] : ");
else
printf ("Steigung [%1.2f [>1.0]] : ", k->ax.rad);
Get_Float (&k->ax.rad);
Print_Vector ("Rotation [∞]",&k->rotate,new);
Get_Vector (&k->rotate);
Print_Float("Skalierung",k->scale,new);
Get_Float(&k->scale);
}
void
Scale_Pyramide (Prims *Obj)
{
VCT3 s;
int i,j;
pyrT *P = Obj->UU.pyrptr;
printf ("Skalierung [xyz] : ");
Get_Vector (&s);
Gravity (Obj);
for (i = 0; i < P->planes; i++)
for (j = 0; j < P->flaechen[0].vertnum; j++)
{
P->flaechen[i].vtx[j].x = (P->flaechen[i].vtx[j].x-Obj->umkugel.m.x)*s.x;
P->flaechen[i].vtx[j].y = (P->flaechen[i].vtx[j].y-Obj->umkugel.m.y)*s.y;
P->flaechen[i].vtx[j].z = (P->flaechen[i].vtx[j].z-Obj->umkugel.m.z)*s.z;
}
}
void
Translate_Pyramide (pyrT *P)
{
VCT3 t;
int i,j;
printf ("Verschiebung [xyz ] : ");
Get_Vector (&t);
for (i = 0; i < P->planes; i++)
for (j = 0; j < P->flaechen[0].vertnum; j++)
vaddeq(&P->flaechen[i].vtx[j],&t);
}
void
Edit_Pyramide (Prims *Act, int new)
{
pyrT *p = Act->UU.pyrptr;
char scale[3],trans[3];
*scale = *trans = 'x';
if (!new)
{
printf ("Skalieren? [j/n] : ");
while (*scale == 'x')
scanf ("%2s",scale);
printf ("Verschieben? [j/n] : ");
while (*trans == 'x')
scanf ("%2s",trans);
if (*scale == 'j')
Scale_Pyramide (Act);
if (*trans == 'j')
Translate_Pyramide (p);
if (*scale == 'j' || *trans == 'j')
return;
Print_Vector ("Links ",&p->flaechen[0].vtx[0],FALSE);
}
else
printf ("Links [xyz] : ");
Get_Vector (&p->flaechen[0].vtx[0]);
p->flaechen[2].vtx[2] = p->flaechen[0].vtx[0];
p->flaechen[3].vtx[2] = p->flaechen[0].vtx[0];
Print_Vector ("Vorn ",&p->flaechen[0].vtx[1],new);
Get_Vector(&p->flaechen[0].vtx[1]);
p->flaechen[1].vtx[0] = p->flaechen[0].vtx[1];
p->flaechen[2].vtx[1] = p->flaechen[0].vtx[1];
Print_Vector("Oben ",&p->flaechen[0].vtx[2],new);
Get_Vector (&p->flaechen[0].vtx[2]);
p->flaechen[1].vtx[2] = p->flaechen[0].vtx[2];
p->flaechen[3].vtx[0] = p->flaechen[0].vtx[2];
Print_Vector("Rechts",&p->flaechen[1].vtx[1],new);
Get_Vector (&p->flaechen[1].vtx[1]);
p->flaechen[2].vtx[0] = p->flaechen[1].vtx[1];
p->flaechen[3].vtx[1] = p->flaechen[1].vtx[1];
}
void
Fill_Box (boxT *bp, BoxInput *b,VCT3 *shear)
{
int i;
for (i = 0; i < 4; i++)
{
bp->flaechen[0].vtx[i].y = b->vorn;
bp->flaechen[1].vtx[i].x = b->rechts;
bp->flaechen[2].vtx[i].y = b->hinten;
bp->flaechen[3].vtx[i].x = b->links;
bp->flaechen[4].vtx[i].z = b->oben;
bp->flaechen[5].vtx[i].z = b->unten;
}
bp->flaechen[0].vtx[0].x = b->links;
bp->flaechen[0].vtx[0].z = b->oben;
bp->flaechen[0].vtx[1].x = b->links;
bp->flaechen[0].vtx[1].z = b->unten;
bp->flaechen[0].vtx[2].x = b->rechts;
bp->flaechen[0].vtx[2].z = b->unten;
bp->flaechen[0].vtx[3].x = b->rechts;
bp->flaechen[0].vtx[3].z = b->oben;
bp->flaechen[1].vtx[0].y = b->vorn;
bp->flaechen[1].vtx[0].z = b->oben;
bp->flaechen[1].vtx[1].y = b->vorn;
bp->flaechen[1].vtx[1].z = b->unten;
bp->flaechen[1].vtx[2].y = b->hinten;
bp->flaechen[1].vtx[2].z = b->unten;
bp->flaechen[1].vtx[3].y = b->hinten;
bp->flaechen[1].vtx[3].z = b->oben;
bp->flaechen[2].vtx[0].x = b->rechts;
bp->flaechen[2].vtx[0].z = b->oben;
bp->flaechen[2].vtx[1].x = b->rechts;
bp->flaechen[2].vtx[1].z = b->unten;
bp->flaechen[2].vtx[2].x = b->links;
bp->flaechen[2].vtx[2].z = b->unten;
bp->flaechen[2].vtx[3].x = b->links;
bp->flaechen[2].vtx[3].z = b->oben;
bp->flaechen[3].vtx[0].y = b->hinten;
bp->flaechen[3].vtx[0].z = b->oben;
bp->flaechen[3].vtx[1].y = b->hinten;
bp->flaechen[3].vtx[1].z = b->unten;
bp->flaechen[3].vtx[2].y = b->vorn;
bp->flaechen[3].vtx[2].z = b->unten;
bp->flaechen[3].vtx[3].y = b->vorn;
bp->flaechen[3].vtx[3].z = b->oben;
bp->flaechen[4].vtx[0].x = b->links;
bp->flaechen[4].vtx[0].y = b->vorn;
bp->flaechen[4].vtx[1].x = b->rechts;
bp->flaechen[4].vtx[1].y = b->vorn;
bp->flaechen[4].vtx[2].x = b->rechts;
bp->flaechen[4].vtx[2].y = b->hinten;
bp->flaechen[4].vtx[3].x = b->links;
bp->flaechen[4].vtx[3].y = b->hinten;
bp->flaechen[5].vtx[0].x = b->links;
bp->flaechen[5].vtx[0].y = b->vorn;
bp->flaechen[5].vtx[1].x = b->links;
bp->flaechen[5].vtx[1].y = b->hinten;
bp->flaechen[5].vtx[2].x = b->rechts;
bp->flaechen[5].vtx[2].y = b->hinten;
bp->flaechen[5].vtx[3].x = b->rechts;
bp->flaechen[5].vtx[3].y = b->vorn;
if (shear != NULL)
{
shear->z = 0;
for (i = 0; i < 4; i++)
{
vaddeq(&bp->flaechen[i].vtx[0],shear);
vaddeq(&bp->flaechen[i].vtx[3],shear);
vaddeq(&bp->flaechen[4].vtx[i],shear);
}
}
}
void
Edit_Box (Prims *Act, int new)
{
BoxInput *b;
boxT *bp = Act->UU.boxptr;
VCT3 shear;
char usr[4];
if (new == TRUE)
{
if ((b = malloc(sizeof(BoxInput))) == NULL)
{
perror("malloc: Quader");
exit(-1);
}
}
else
b = &B1;
Print_Float("x: Links ",b->links,new);
Get_Float (&b->links);
Print_Float("x: Rechts",b->rechts,new);
Get_Float (&b->rechts);
Print_Float("y: Vorn ",b->vorn,new);
Get_Float (&b->vorn);
Print_Float("y: Hinten",b->hinten,new);
Get_Float (&b->hinten);
Print_Float("z: Oben ",b->oben,new);
Get_Float (&b->oben);
Print_Float("z: Unten ",b->unten,new);
Get_Float(&b->unten);
printf("Quader verzerren? [j/n]: ");
scanf("%3s",usr);
if (*usr == 'j')
{
printf("xy-Verschiebung des Deckels [xyz]: ");
Get_Vector(&shear);
shear.z = 0;
}
else
shear.x = shear.y = shear.z = 0;
Fill_Box(bp,b,&shear);
if (new)
free (b);
}
void // Rotation fehlt noch
Edit_Super (Prims *Act, int new)
{
superT *s = Act->UU.supptr;
float val1,val2;
char usr[4];
if (new)
{
s->box.Lower_Left.x = s->box.Lower_Left.y = s->box.Lower_Left.z = -1.;
s->box.Lengths.x = s->box.Lengths.y = s->box.Lengths.z = 1.;
printf ("Mittelpunkt [xyz] : ");
}
else
Print_Vector ("Mittelpunkt",&s->m,FALSE);
Get_Vector (&s->m);
printf ("Exponenten [konvex: 0.05 < Exp < 1.0; konkav: 1.0 < Exp < 7.0]\n");
val1 = 2./s->Power.x;
if (new)
printf("West-Ost : ");
else
printf("West-Ost [%2.3f] : ",val1);
Get_Float (&val1);
(val1 > 7) ? (val1 = 7) : (val1 < 0.05) ? (val1 = 0.05) : val1;
s->Power.x = 2./val1;
val2 = 2./s->Power.z;
if (new)
printf("Nord-Sued : ");
else
printf("Nord-Sued [%2.3f] : ",val2);
Get_Float (&val2);
(val2 > 7) ? (val2 = 7) : (val2 < 0.05) ? (val2 = 0.05) : val2;
s->Power.z = 2./val2;
s->Power.y = val1/val2;
printf ("Skalieren [j/n] : ");
scanf ("%2s",usr);
if (*usr == 'j')
{
if (!new)
Print_Vector ("Skalierung",&s->scal,FALSE);
else
printf("Skalierung [xyz] : ");
Get_Vector (&s->scal);
}
else
s->scal.x = s->scal.y = s->scal.z = 1.;
}
void
Edit_Sor (Prims *Act, int new, int erst)
{
char usr[3];
uint i,hilf,punkte = SOR_POINTS;
sorInput *SI;
VCT3 scale = { 2,2,2 };
VCT3 translate = { 0,0,2 };
VCT3 rotate = { 90,0,0};
if (new)
{
if ((SI = malloc(sizeof(sorInput))) == NULL)
{
perror("malloc: SOR-Eingabe");
exit(-1);
}
}
else
SI = &sorI;
if (!erst)
{
printf("offen oder geschlossen?");
if (!new)
{
if (SI->closed)
printf(" [geschlossen]");
else
printf(" [offen]");
}
printf(" [o/g] : ");
scanf("%2s",usr);
if (*usr == 'o' || *usr == 'j')
SI->closed = FALSE;
else
SI->closed = TRUE;
if (!new)
{
printf("Punkte edieren? [j/n] : ");
scanf("%2s",usr);
}
if (new || *usr == 'j' || *usr == 'e')
{
if (new)
printf("4 < Punktanzahl < %u : ",punkte);
else
printf("4 < Punktanzahl [%hd] < %u : ",SI->Number,punkte);
scanf("%u",&hilf);
(hilf < 4) ? (hilf = 4) : (hilf >= punkte) ? (hilf = punkte-1) : hilf;
SI->Number = hilf;
printf("Regel: Abszissen muessen monoton wachsen [0. <= y <= 1.\n");
printf("%u Ordinaten und Abszissen:\n",SI->Number);
for (i = 0; i < SI->Number; i++)
{
printf("%u: ",i+1);
if (!new)
printf ("[%1.3f %1.3f ] ",SI->P[i].x,SI->P[i].y);
Get_VCT2 (&SI->P[i]);
if (i)
{
if (SI->P[i].y < SI->P[i-1].y)
{
printf("Abszisse zu klein: Eingabe %u wiederholen!\n",i+1);
--i;
}
}
}
}
}
Compute_Sor (SI,Act);
Create_Transform (&Act->transform);
if (!erst)
{
printf("Rotieren? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
{
if (!new)
Print_Vector("Rotation [∞]",&rotate,FALSE);
else
printf("Rotation [xyz [∞]: ");
Get_Vector (&rotate);
}
}
Rotate_Object (Act,&rotate);
if (!erst)
{
printf("Skalieren? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
{
if (!new)
Print_Vector("Skalierung ",&scale,FALSE);
else
printf("Skalierung [xyz] : ");
Get_Vector (&scale);
}
}
Scale_Object (Act,&scale);
if (!erst)
{
printf("Verschieben? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
{
if (!new)
Print_Vector ("Translation ",&translate,FALSE);
else
printf("Translation [xyz] : ");
Get_Vector (&translate);
}
}
Translate_Object (Act,&translate);
// provisorisch
Act->umkugel.m = translate;
if (scale.x >= scale.y && scale.x >= scale.z)
Act->umkugel.rad = scale.x;
else if (scale.y >= scale.z)
Act->umkugel.rad = scale.y;
else
Act->umkugel.rad = scale.z;
if (new)
free(SI);
}
void
Edit_Disc (Prims *Act, int new)
{
discT *k = Act->UU.discptr;
Print_Vector ("Mittelpunkt",&k->ax.m,new);
Get_Vector (&k->ax.m);
Print_Float("Radius",k->ax.rad,new);
Get_Float (&k->ax.rad);
Print_Float("Innenradius [0 <= x < Radius]",k->irad,new);
Get_Float (&k->irad);
Print_Vector ("Normale",&k->normal,new);
Get_Vector (&k->normal);
}
void
Edit_Lemni (Prims *Act, int new)
{
lemniT *k = Act->UU.lemniptr;
Print_Vector ("Mittelpunkt",&k->ax.m,new);
Get_Vector (&k->ax.m);
Print_Float("Radius",k->ax.rad,new);
Get_Float (&k->ax.rad);
Print_Vector ("Rotation [∞]",&k->rotate,new);
Get_Vector (&k->rotate);
}
void
Init_Surface (Prims *Act)
{
char usr[4];
printf ("Einzeloberflaeche edieren? [j/n] : ");
scanf("%2s",usr);
if (*usr == 'j')
Edit_Surface(0,Act);
}
void
Init_Moebius (Prims *Act)
{
if ((Act->UU.moeptr = malloc(sizeof(moeT))) != NULL)
{
Edit_Moebius (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Moebius");
exit(-1);
}
void
Init_Steiner (Prims *Act)
{
if ((Act->UU.steiptr = malloc(sizeof(steiT))) != NULL)
{
Edit_Steiner (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Steiner");
exit(-1);
}
void
Init_Torus (Prims *Act)
{
if ((Act->UU.torptr = malloc(sizeof(torT))) != NULL)
{
Edit_Torus (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Torus");
exit(-1);
}
void
Init_Ellipsoid (Prims *Act)
{
if ((Act->UU.ellptr = malloc(sizeof(ellT))) != NULL)
{
Edit_Ellipsoid (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Ellipsoid");
exit(-1);
}
void
Init_Kegel (Prims *Act)
{
if ((Act->UU.coneptr = malloc(sizeof(coneT))) != NULL)
{
Edit_Kegel (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Kegel");
exit(-1);
}
void
Init_Agnesi (Prims *Act)
{
if ((Act->UU.agnptr = malloc(sizeof(agnT))) != NULL)
{
Edit_Agnesi (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Agnesi");
exit(-1);
}
void
Init_Pyramide (Prims *Act)
{
if ((Act->UU.pyrptr = malloc(sizeof(pyrT))) != NULL)
{
Edit_Pyramide (Act, TRUE);
Init_Surface (Act);
return;
}
perror("malloc: Pyramide");
exit(-1);
}
void
Init_Box (Prims *Act)
{
if ((Act->UU.boxptr = malloc(sizeof(boxT))) != NULL)
{
Edit_Box (Act, TRUE);
Init_Surface (Act);
return;
}
perror("malloc: Quader");
exit(-1);
}
void
Init_Super (Prims *Act)
{
if ((Act->UU.supptr = malloc(sizeof(superT))) != NULL)
{
Edit_Super (Act, TRUE);
Init_Surface (Act);
return;
}
perror("malloc: Superellipsoid");
exit(-1);
}
void
Init_Sor (Prims *Act)
{
if ((Act->UU.sorptr = malloc(sizeof(sorT))) != NULL)
{
Edit_Sor (Act, TRUE, FALSE);
Init_Surface (Act);
return;
}
perror ("malloc: SOR");
exit(-1);
}
void
Init_Disc (Prims *Act)
{
if ((Act->UU.discptr = malloc(sizeof(discT))) != NULL)
{
Edit_Disc (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Scheibe");
exit(-1);
}
void
Init_Lemni (Prims *Act)
{
if ((Act->UU.lemniptr = malloc(sizeof(lemniT))) != NULL)
{
Edit_Lemni (Act, TRUE);
Init_Surface (Act);
return;
}
perror ("malloc: Lemniskate");
exit(-1);
}
Prims *
Start_Prims (int typ) // Davignon, UNIX C, 143
{
int Nr,Form;
Prims *Obj;
char zahl[8];
if (typ > TestFormCnt)
return NULL;
if (!(Obj = malloc (sizeof(Prims))))
{
perror("malloc: Objekt");
exit(-1);
}
if (!arg && ObjCnt == 3) // konstante Zeitmess-Verhaeltnisse
printf("Oberflaeche fuer %s [ 5] : ",ObjStr[typ]);
else
printf("Oberflaeche fuer %s [%2u] : ",ObjStr[typ],normal[typ]);
scanf("%4s",zahl);
if (*zahl == 'n')
Nr = normal[typ];
else
Nr = strtol(zahl,NULL,0);
(Nr > SurfCnt) ? (Nr = SurfCnt) : (Nr < 0) ? (Nr = 0) : Nr;
if ((Obj->surfptr = malloc(sizeof(SurfT))) == NULL)
{
perror("malloc: Oberflaeche");
exit(-1);
}
memcpy(Obj->surfptr,SurfList[Nr],sizeof(SurfT));
if (Obj->surfptr->FarbTyp & REFMAP)
Obj->surfptr->ColProc = D2MapProc;
switch (typ)
{
// Notloesungen
case 0:
Obj->form = sky;
Himmel = Obj;
Obj->prev = Obj->next = NULL;
if (Obj->surfptr->ColProc == D2MapProc)
loadtexture(Obj);
else if (Obj->surfptr->ColProc == EqOdProc && Nr != 2)
{
vscaleeq(&Obj->surfptr->Od,2);
schranke(&Obj->surfptr->Od);
}
break;
case 1: Obj->form = hell; Hoelle = Obj; break;
case 2: Obj->form = ground; Boden = Obj; break;
// ab hier okay
case 3: Obj->form = sphere; break;
case 4: Obj->form = moebius; break;
case 5: Obj->form = steiner; break;
case 6: Obj->form = torus; break;
case 7: Obj->form = ellipsoid; break;
case 8: Obj->form = kegel; break;
case 9: Obj->form = pyramide; break;
case 10:Obj->form = box; break;
case 11:Obj->form = agnesi; break;
case 12:Obj->form = super; break;
case 13:Obj->form = sor; break;
case 14:Obj->form = disc; break;
case 15:Obj->form = lemni; break;
default: ; // hier weitere Formen
}
Form = FormCnts[typ];
switch (Obj->form)
{
case sphere:
if (!Form)
Obj->umkugel = k1;
else if (Form == 1)
Obj->umkugel = k2;
else
{
Edit_Kugel (Obj, TRUE);
Init_Surface (Obj);
}
break;
case moebius:
if (!Form)
Obj->UU.moeptr = &moeb;
else
Init_Moebius (Obj);
break;
case steiner:
if (!Form)
Obj->UU.steiptr = &stei;
else
Init_Steiner (Obj);
break;
case torus:
if (!Form)
Obj->UU.torptr = &tor;
else
Init_Torus (Obj);
break;
case ellipsoid:
if (!Form)
Obj->UU.ellptr = &ell;
else
Init_Ellipsoid(Obj);
break;
case kegel:
if (!Form)
Obj->UU.coneptr = &cone;
else
Init_Kegel(Obj);
break;
case pyramide:
if (!Form)
Obj->UU.pyrptr = &pyr;
else
Init_Pyramide(Obj);
break;
case box:
if (!Form)
{
Obj->UU.boxptr = &box1;
Fill_Box(&box1,&B1,NULL);
}
else
Init_Box(Obj);
break;
case agnesi:
if (!Form)
Obj->UU.agnptr = &agn;
else
Init_Agnesi(Obj);
break;
case super:
if (!Form)
Obj->UU.supptr = &sup;
else
Init_Super (Obj);
break;
case sor:
if (!Form)
{
if ((Obj->UU.sorptr = malloc (sizeof(sorT))) == NULL)
{
perror("malloc: SOR");
exit(-1);
}
Edit_Sor (Obj,FALSE,TRUE);
}
else
Init_Sor (Obj);
break;
case disc:
if (!Form)
Obj->UU.discptr = &scheibe;
else
Init_Disc (Obj);
break;
case lemni:
if (!Form)
Obj->UU.lemniptr = &lemnis;
else
Init_Lemni (Obj);
break;
default: ; // hier weitere Formen
}
Gravity (Obj);
++ObjCnt;
++FormCnts[typ];
return Obj;
}
void
Add_Prim (Prims *Act, int typ) // Davignon, UNIX C, 146
{
Prims *New;
New = Start_Prims (typ);
New->prev = Act;
New->next = Act->next;
if (Act->next != NULL)
Act->next->prev = New;
Act->next = New;
Last = Act = New;
if (Act->surfptr->ColProc == D2MapProc && Act->surfptr->text == NULL)
loadtexture(Act);
}
void
Init_Surf_Global (void)
{
char weiter[4],zahl[8];
int nr;
printf("Moegliche Objekte: \n");
printf(" 0: Himmel 1: Boden 2: Hoelle 3: Kugel 4: Moebius 5: Steiner\n");
printf(" 6: Torus 7: Ellipsoid 8: Kegel 9: Pyramide 10: Quader 11: Agnesi\n");
printf(" 12: SuperEll 13: Rotation 14: Scheibe 15: Lemnisk.\n");
printf("Moegliche Oberflaechen: \n");
printf(" 0: %s 1: %s 2: %s 3: %s 4: %s 5: %s\n",
SurfStr[0],SurfStr[1],SurfStr[2],SurfStr[3],SurfStr[4],SurfStr[5]);
printf(" 6: %s 7: %s 8: %s 9: %s 10: %s 11: %s\n",
SurfStr[6],SurfStr[7],SurfStr[8],SurfStr[9],SurfStr[10],SurfStr[11]);
printf(" 12: %s 13: %s 14: %s 15: %s 16: %s 17: %s\n",
SurfStr[12],SurfStr[13],SurfStr[14],SurfStr[15],SurfStr[16],SurfStr[17]);
printf(" 18: %s 19: %s 20: %s 21: %s 22: %s 23: %s\n",
SurfStr[18],SurfStr[19],SurfStr[20],SurfStr[21],SurfStr[22],SurfStr[23]);
printf(" 24: %s 25: %s 26: %s 27: %s\n", SurfStr[24],SurfStr[25],SurfStr[26],
SurfStr[27]);
printf ("Oberflaechen global edieren? [j/n] : ");
scanf ("%2s",weiter);
while (*weiter == 'j' || *weiter == 'e')
{
printf ("Oberflaechennummer [0-%d] : ",SurfCnt);
scanf ("%3s",zahl);
if ((nr = strtol(zahl,NULL,0)) > SurfCnt)
nr = SurfCnt;
Edit_Surface (nr,NULL);
printf ("Weitere Oberflaeche edieren? [j/n] : ");
scanf ("%2s",weiter);
}
}
void
Init_Objects (void)
{
int Typ;
Prims *Act = NULL;
char zahl[8],weiter[4] = "j";
while (*weiter == 'j')
{
switch (ObjCnt)
{
case 0:
Act = Start_Prims (ObjCnt); break;
case 1: case 2:
Add_Prim (Act, ObjCnt); break;
case 11:
if (!arg)
return;
default:
printf ("Noch ein Objekt anlegen? [j/n] : ");
scanf ("%2s",weiter);
if (*weiter != 'n')
{
printf ("Objektform [3-%2d]: ",
TestFormCnt);
scanf ("%3s",zahl);
((Typ = strtol(zahl,NULL,0)) < 3) ? (Typ = 3) :
(Typ > TestFormCnt) ? (Typ = TestFormCnt) : Typ;
Add_Prim (Act, Typ);
}
}
}
}
void
Delete_Prims (Prims *Root)
{
int Form;
while (Root->next)
{
Root = Root->next;
--FormCnts[Root->prev->form];
Form = FormCnts[Root->prev->form];
if (Root->prev->surfptr)
free (Root->prev->surfptr);
switch (Root->prev->form)
{
case lemni:
if (Form)
free(Root->prev->UU.lemniptr);
break;
case sor:
free (Root->prev->UU.sorptr->Spline->Entry);
free (Root->prev->UU.sorptr->Spline);
free (Root->prev->UU.sorptr); // Ausnahme: alle sorptr alloziert
break;
case disc:
if (Form)
free(Root->prev->UU.discptr);
break;
case super:
if (Form)
free (Root->prev->UU.supptr);
break;
case agnesi:
if (Form)
free (Root->prev->UU.agnptr);
break;
case box:
if (Form)
free (Root->prev->UU.boxptr);
break;
case pyramide:
if (Form)
free (Root->prev->UU.pyrptr);
break;
case kegel:
if (Form)
free (Root->prev->UU.coneptr);
break;
case ellipsoid:
if (Form)
free (Root->prev->UU.ellptr);
break;
case torus:
if (Form)
free (Root->prev->UU.torptr);
break;
case steiner:
if (Form)
free (Root->prev->UU.steiptr);
break;
case moebius:
if (Form)
free (Root->prev->UU.moeptr);
break;
default: ;
}
free (Root->prev);
}
free (Root);
ObjCnt = 0;
}
// 4. Lampen
void
Edit_Lamp (LampT *L,int new)
{
Print_Vector ("RGB-Farben ",&L->LightC,new | COLOUR);
Get_Vector (&L->LightC);
Print_Vector ("Koordinaten",&L->LightV,new);
Get_Vector (&L->LightV);
#ifdef JITTER
Print_Float ("Radius [<1.0]",L->rad,new);
Get_Float (&L->rad);
#endif
}
LampT *
Start_Lamp (void)
{
LampT *New;
char weit[3];
if ((New = malloc (sizeof(LampT))) == NULL)
{
perror ("malloc: Lampe");
exit (-1);
}
if (LampCnt < 2)
printf ("Lampe edieren? [j/n] : ");
*weit = 'x';
switch(LampCnt)
{
case 0:
scanf ("%2s",weit);
if (*weit == 'j' || *weit == 'e')
Edit_Lamp (&L1,FALSE);
*New = L1;
break;
case 1:
scanf("%2s",weit);
if (*weit == 'j' || *weit == 'e')
Edit_Lamp (&L2,FALSE);
*New = L2;
break;
default:
Edit_Lamp (New, TRUE);
}
New->next = NULL;
New->Shad = NULL;
++LampCnt;
New->LightN = New->LightV;
normalize (&New->LightN);
return New;
}
void
Add_Lamp (LampT *New)
{
LampT *Lmp = Start_Lamp ();
Lmp->next = New->next;
New = New->next = Lmp;
}
void
Delete_Lamps (LampT *LStart)
{
LampT *Tmp;
while (LStart->next != NULL)
{
Tmp = LStart;
LStart = LStart->next;
free (Tmp);
}
free (LStart);
LampCnt = 0;
}
void
Init_Lamps (void)
{
LampT *New;
char answ[3];
New = Lampen = Start_Lamp();
do
{
printf ("Noch eine Lampe setzen? [j/n] : ");
scanf ("%2s",answ);
if (*answ == 'j')
Add_Lamp (New);
}
while (*answ == 'j');
if (LampCnt > 1)
LampDiv = 1.0/(float)LampCnt;
}
// 5. Sonderfunktionen
void
Init_View (VCT3 *vh, VCT3 *vr)
{
ray.p = Frame.eye;
errEps (Frame.eye.z);
vh->x = -Frame.eye.x;
vh->y = -Frame.eye.y;
vh->z = vdot(&Frame.eye,&Frame.eye);
normalize (vh);
if (Frame.eye.z < 0)
vneg (vh);
vcross (vr,vh,&Frame.eye);
normalize (vr);
}
#ifdef GAMMA
VCT3 Gamma = {1.,0.91,0.91};
void
Correct_Gamma (void)
{
int i;
SurfT *S;
for (i = 0; i < SurfCnt; i++)
{
S = &Sky + i;
S->Od.x *= Gamma.x;
S->Od.y *= Gamma.y;
S->Od.z *= Gamma.z;
S->SpecC.x *= Gamma.x;
S->SpecC.y *= Gamma.y;
S->SpecC.z *= Gamma.z;
S->TransC.x *= Gamma.x;
S->TransC.y *= Gamma.y;
S->TransC.z *= Gamma.z;
}
for (i = 0; i < 4; i++)
{
MarbleCols[i].c.x *= Gamma.x;
MarbleCols[i].c.y *= Gamma.y;
MarbleCols[i].c.z *= Gamma.z;
}
for (i = 0; i < 4; i++)
{
HellCols[i].c.x *= Gamma.x;
HellCols[i].c.y *= Gamma.y;
HellCols[i].c.z *= Gamma.z;
}
for (i = 0; i < 6; i++)
{
FlameCols[i].c.x *= Gamma.x;
FlameCols[i].c.y *= Gamma.y;
FlameCols[i].c.z *= Gamma.z;
}
}
#endif
void
Init_Ring (void) // baut Schattenring auf
{
Prims *Act,*New;
if (!(Last = Ring = malloc(sizeof(Prims))))
{
perror ("malloc: Ring");
exit (-1);
}
memcpy (Ring, Himmel->next,sizeof(Prims));
Act = Himmel->next;
++RingCnt;
if (ObjCnt > 4) // mehr als Himmel,Hoelle,Boden plus 1 Objekt
{
Ring->prev = Ring->next = NULL;
do
{
if ((New = malloc(sizeof(Prims))) == NULL)
{
perror("malloc: Ring");
exit(-1);
}
memcpy (New,Act->next,sizeof(Prims));
New->prev = Last;
New->next = NULL;
Act = Act->next;
Last = New;
++RingCnt;
}
while (Act->next->form != ground);
Ring->prev = New;
New->next = Ring;
}
else
Ring->prev = Ring->next = Ring;
}
// experimentell aus korrigiertem Glassner, 232f.
#ifdef OHTA
void
Init_Ohta (void)
{
int i,j;
dirT Dir;
volatile float dist,radsum;
Prims *N,*P = Ring;
if ((direction = (dirT**)calloc(RingCnt,sizeof(dirT*))) == NULL)
{
perror("calloc");
exit(-1);
}
for (i = 0; i < RingCnt; i++)
{
if ((direction[i] = (dirT*)calloc(RingCnt,sizeof(dirT))) == NULL)
{
perror("calloc");
exit(-1);
}
P->ring = i;
N = Ring;
for (j = 0; j < RingCnt; j++)
{
Dir.costheta = Dir.dist.x = Dir.dist.y = Dir.dist.z = 1;
if (i != j && P->form != ground && P->form != sor)
{
if (N->form != ground && N->form != sor)
{
radsum = P->umkugel.rad + N->umkugel.rad;
// bei D=N-P verschwinden alle Reflexionen
dist = vsubnorm(&Dir.dist,&P->umkugel.m,&N->umkugel.m);
if (dist > radsum) // Umkugeln disjunkt
Dir.costheta = sqrt(1-(radsum/dist)); // 13.08.04
}
}
direction[i][j] = Dir;
N = N->prev;
}
P = P->prev;
}
}
#endif
void
Delete_Ring (void)
{
int i = RingCnt;
Prims *Tmp = Ring;
#ifdef OHTA
int j;
for (j = 0; j < i; j++)
free(direction[j]);
free(direction);
#endif
for (; i > 0; i--)
{
Tmp = Tmp->prev;
if (Tmp->next != NULL && Tmp->next->surfptr->text == NULL)
{ // SIGSEGV-Gefahr!
free (Tmp->next);
Tmp->next = NULL;
}
}
Ring = NULL;
RingCnt = 0;
}
char
Init_Lattice (void)
{
int i,j,k;
for (i = 0; i < LatCnt; i++)
for (j = 0; j < LatCnt; j++)
for (k = 0; k < LatCnt; k++)
Lattice[i][j][k] = (char)rand();
return TRUE;
}
void
Edit_Normal (SurfT *S)
{
char usr[4];
printf("Normalenprozeduren:\n");
printf("0: Schlicht 1: Wellen 2: Regen 3: Teich 4: Sand 5: Quilt");
printf("\nWelche Normalenprozedur? [0-5] : ");
scanf("%2s",usr);
switch (strtol(usr,NULL,0))
{
case 0: S->NrmProc = EqNrmProc; break;
case 1: S->NrmProc = WaveProc; break;
case 2: S->NrmProc = RainProc; break;
case 3: S->NrmProc = PondProc; break;
case 4: S->NrmProc = SandProc; break;
case 5: S->NrmProc = QuiltProc; break;
default: ;
}
}
void // Davignon, UNIX C, 147, ohne free()
Delete_Predef (Prims *P)
{
P->next->prev = P->prev;
P = P->next;
P->prev->next = P;
--ObjCnt;
}
void
Edit_Predefs (void) // verwaltet global deklarierte Objekte
{
Prims *P;
char frame[3],Normal[3];
for (P = Boden; P != NULL; P = P->prev) // nur von Boden bis Himmel
{ // Hoellennormale uninteressant
*frame = *Normal = 'x';
if (P->form > ground)
{
printf("%*s %-s",strlen(ObjStr[P->form]),ObjStr[P->form],
"edieren oder loeschen? [j/l/n]: ");
scanf("%2s",frame);
}
if (*frame == 'l')
--FormCnts[P->form];
if (*frame == 'e')
*frame = 'j';
switch (P->form)
{
case sphere:
if (memcmp((void*)&P->umkugel,(void*)&k1,sizeof(kugelT))
&& (memcmp((void*)&P->umkugel,(void*)&k2,sizeof(kugelT))))
break;
if (*frame == 'j')
Edit_Kugel (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case moebius:
if (P->UU.moeptr != &moeb)
break;
if (*frame == 'j')
Edit_Moebius (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case steiner:
if (P->UU.steiptr != &stei)
break;
if (*frame == 'j')
Edit_Steiner (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case torus:
if (P->UU.torptr != &tor)
break;
if (*frame == 'j')
Edit_Torus (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case ellipsoid:
if (P->UU.ellptr != &ell)
break;
if (*frame == 'j')
Edit_Ellipsoid (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case kegel:
if (P->UU.coneptr != &cone)
break;
if (*frame == 'j')
Edit_Kegel (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case pyramide:
if (P->UU.pyrptr != &pyr)
break;
if (*frame == 'j')
Edit_Pyramide (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case box:
if (P->UU.boxptr != &box1)
break;
if (*frame == 'j')
Edit_Box (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case agnesi:
if (P->UU.agnptr != &agn)
break;
if (*frame == 'j')
Edit_Agnesi (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case super:
if (P->UU.supptr != &sup)
break;
if (*frame == 'j')
Edit_Super (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case sor:
if (P->UU.sorptr->Entry)
break;
if (*frame == 'j')
Edit_Sor (P,FALSE,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case disc:
if (P->UU.discptr != &scheibe)
break;
if (*frame == 'j')
Edit_Disc (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
case lemni:
if (P->UU.lemniptr != &lemnis)
break;
if (*frame == 'j')
Edit_Lemni (P,FALSE);
else if (*frame == 'l')
Delete_Predef(P);
break;
default: ;
}
if (*frame == 'j')
Init_Surface(P);
if (*frame != 'l')
{
printf("Neue Normale fuer %s\b [j/n] : ",ObjStr[P->form]);
scanf("%2s",Normal);
if (*Normal == 'j')
Edit_Normal (P->surfptr);
}
Gravity (P);
}
}
int
main (int argc,char **argv)
{
const float xmax = SPALTEN-1.;
const float ymax = ZEILEN-1.;
char name[32],spei[4],frame[4];
VCT3 vh,vr,hv,nh;
float aspect;
// #ifndef DEBUG
VCT3 c;
// #endif
clock_t seconds;
if (argc > 1) // Lattice unabhaengig von Random-Zeit
{
TestFormCnt = 9;
arg = FALSE;
}
else
randomize ();
printf("Raytracer Himmel und Hoelle\n");
Init_Lamps ();
if (!Init_Lattice())
{
perror("malloc: Lattice");
exit(-1);
}
printf ("Fertiges Bild speichern? [j/n] : ");
scanf ("%2s",spei);
if (*spei == 'j')
{
printf ("Dateiname : ");
scanf ("%31s",name);
}
// Oberflaechen erfragen und initialisieren
#ifdef GAMMA
Correct_Gamma ();
#endif
#ifdef TESTSSE
init_sse();
#endif
Init_Surf_Global ();
// Texturen initialisieren
GenColTab (4-1,MarbleTab,MarbleCols);
GenColTab (4-1,HellTab,HellCols);
GenColTab (6-1,FlameTab,FlameCols);
Init_Objects ();
printf ("Objekte [in Eingabefolge] edieren? [j/n] : ");
scanf("%2s",frame);
if (*frame == 'j' || *frame == 'e')
Edit_Predefs ();
printf ("Betrachter edieren? [j/n] : ");
scanf ("%2s",frame);
if (*frame == 'j' || *frame == 'e')
Edit_Frame ();
Init_View (&vh,&vr);
Init_Fresnel (); // vor Init_Ring()!
Init_Ring ();
#ifdef OHTA
Init_Ohta ();
#endif
// Umschaltung nach Graphik
strncpy(Program_Name,*argv,23);
if (video(SPALTEN,ZEILEN) < 0)
return -1;
// Bildschirm-Schleife
aspect = ymax/xmax * Frame.PicSizeWC * Frame.Aspect;
seconds = clock();
for (y = 0; y < ZEILEN; y++)
{
if (taste())
{
blau();
return 0;
}
vscale (&hv,&vh,(float)((halb-y/ymax) * aspect));
for (x = 0; x < SPALTEN; x++)
{
vscale (&nh,&vr,(float)((x/xmax-halb) * Frame.PicSizeWC));
vaddeq (&nh,&hv);
vsubnorm (&ray.n,&nh,&Frame.eye);
trace (ray,1,&c);
#ifdef HICOL
schranke (&c);
#endif
amulset (x,y,&c);
}
}
seconds = clock()-seconds;
if (*spei == 'j')
savepic (name,0,0,SPALTEN,ZEILEN);
while (!taste());
blau();
printf ("Sekunden: %.3f\n",(float)(seconds/(float)CLOCKS_PER_SEC));
// #ifdef DEBUG
// printf("Strahlen: %lu, Reflexe: %lu, Refraktionen: %lu Kohaerenzen: %lu\n",
// nr_of_rays,nr_of_refl,nr_of_refr,nr_of_coh);
// printf("Inkohaerenzen: %lu\n",nr_of_rest);
// #endif
Delete_Prims (Himmel);
Delete_Lamps (Lampen);
Delete_Ring ();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment