Created
February 20, 2020 22:49
-
-
Save markcmarino/d97919977181c9efc842238e77f4f6ad to your computer and use it in GitHub Desktop.
Translation of Friedrich Kittler's xsuptrace.c ray tracer code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 = ℓ | |
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 = ⊃ | |
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