|
|
While there are not many such platforms left, those who still need them and
have ISO C99 compatible libraries may want to try to adjust the ot_index_box
function in octree.cpp to use the logbf / ilogbf C99 library function, which
is available in most recent compilers for Unix platforms. below is the
example code that demonstrates how to adapt the code. The actual POV-Ray
code change is left as an exercise to the reader ;-)
Thorsten
NOTE: Be aware that is is most likely far less efficient, but it is
compatible with ISO C99 libraries! I only provide the version using logbf
because the library I used for testing listed ilogbf as not yet supported...
#include <stdio.h>
#include <math.h>
int main(void)
{
union
{
float f;
long l;
}
convert;
convert.f = -8614.585434574;
convert.l &= 0xff800000;
printf("%f %f\n", pow(2.0, logbf(convert.f) *(1-2*signbit(convert.f)),
convert.f);
convert.f = -84.585434574;
convert.l &= 0x7f800000;
printf("%f %x %d %d %d\n", convert.f, convert.l, (convert.l>>23)-127,
(convert.l>>23), ((int)logbf(convert.f))+127);
return 0;
}
____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde
Visit POV-Ray on the web: http://mac.povray.org
Post a reply to this message
|
|
|
|
In article <3D8EE425.117C3945@gmx.de> , Christoph Hormann
<chr### [at] gmxde> wrote:
> I don't know much about these different floating point formats, but
> remember this part was exactly what caused problems when i last tried
> using POV-Ray on a SGI machine. Will your suggestion help there or is
> that a different (64 bit specific) problem?
No, it also resolves the 64 bit specific problems. Actually, the code below
may even work on 64 bit systems as is, because the actual bug was that the
conversion structure used 'long' rather than 'int', so it would attempt to
modify 64 bit data while it should have modified 32 bit data.
Replace the existing code with the functions shown below. They should work
just fine now. however, as a lack a 64 bit system to test on, I cannot tell
you for sure :-(
Thorsten
/**************************************************************************
* Local preprocessor defines
***************************************************************************/
// WARNING: The default uses POV-Ray's own tricks which only work if
// "float" is a 32 bit IEEE 754 floating point number! If your platform
// does not use 32 bit IEEE 754 floating point numbers, radiosity will
// be broken!!! If you have this problem, your only other choice is to
// use an ISO C99 standard revision compatible compiler and library:
//
// Define this to 1 to use ISO C99 functions logbf, logb and copysign.
// Define this to 2 to use ISO C99 functions ilogbf, ilogb and copysign.
//
// You may want to try 1 and 2 as it cannot be generally said which one
// will be faster, but it is most likely that either 1 or 2 will perform
// slightly less well than POV-Ray's trick. In any case, testing all
// variants (0, 1 and 2) is recommended if possible on your platform!
//
// NOTE: Of course you should put the define forC99_COMPATIBLE_RADIOSITY
// into config.h and *not* mess around with this file!!!
#ifndef C99_COMPATIBLE_RADIOSITY
#define C99_COMPATIBLE_RADIOSITY 0
#endif
int ot_point_in_node(VECTOR point, OT_ID *id)
{
DBL sized, minx, miny, minz, lox, loy, loz, hix, hiy, hiz;
#if(C99_COMPATIBLE_RADIOSITY == 0)
union
{
float f;
int l;
}
size; /* MUST be float, NOT DBL */
size.l = id->Size << 23;
sized = (DBL) size.f;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
sized = pow(2.0, id->Size);
#else
sized = (DBL)(1 << id->Size);
#endif
minx = (DBL) id->x * sized - OT_BIAS;
miny = (DBL) id->y * sized - OT_BIAS;
minz = (DBL) id->z * sized - OT_BIAS;
lox = minx - sized * .5;
hix = minx + sized * 1.5;
loy = miny - sized * .5;
hiy = miny + sized * 1.5;
loz = minz - sized * .5;
hiz = minz + sized * 1.5;
return(point[X] >= lox && point[X] < hix &&
point[Y] >= loy && point[Y] < hiy &&
point[Z] >= loz && point[Z] < hiz);
}
void ot_index_box(VECTOR min_point, VECTOR max_point, OT_ID *id)
{
int done, idx, idy, idz;
float dx, dy, dz, maxdel; /* MUST BE "float" NOT "DBL" */
DBL bsized, maxord;
#if(C99_COMPATIBLE_RADIOSITY == 0)
union
{
float f;
int l;
}
convert;
#endif
OT_ID base_id, test_id;
dx = (float) (max_point[X] - min_point[X]);
dy = (float) (max_point[Y] - min_point[Y]);
dz = (float) (max_point[Z] - min_point[Z]);
maxdel = MAX3(dx, dy, dz);
/*
* This hex operation does a floor to next lower power of 2, by clearing
* all of the mantissa bits. Works only on IEEE single precision floats
*/
#if(C99_COMPATIBLE_RADIOSITY == 0)
convert.f = maxdel;
convert.l &= 0xff800000;
bsized = (DBL)convert.f;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
bsized = pow(2.0, logbf(maxdel));
bsized = copysign(bsized, maxdel);
#else
bsized = (DBL)(1 << ilogbf(maxdel));
bsized = copysign(bsized, maxdel);
#endif
#ifdef SAFE_METHOD
/*
* This block checks for the case where the node id would cause integer
* overflow, since it is a small buffer far away
*/
maxord = MAX3(fabs(min_point[X]), fabs(min_point[Y]), fabs(min_point[Z]));
maxord += OT_BIAS;
while (maxord / bsized > 1000000000.0)
{
#ifdef RADSTATS
overflows++;
#endif
bsized *= 2.0;
}
#endif
/* calculate the smallest possible node that the item might fit into */
base_id.x = (int) floor((min_point[X] + OT_BIAS) / bsized);
base_id.y = (int) floor((min_point[Y] + OT_BIAS) / bsized);
base_id.z = (int) floor((min_point[Z] + OT_BIAS) / bsized);
/*
* This magic hex operation extracts the exponent, which gives us an
* integer number suitable for labelling a range of a power of 2. In IEEE
* format, value = pow(2,exponent-127). Therefore, if our index is, say,
* 129, then the item has a maximum extent of (2 to the (129-127)), or
* about 4 space units.
*/
#if(C99_COMPATIBLE_RADIOSITY == 0)
convert.f = (float) bsized;
base_id.Size = (convert.l & 0x7f800000) >> 23;
#elif(C99_COMPATIBLE_RADIOSITY == 1)
base_id.Size = ((int)logb(bsized)) + 127;
#else
base_id.Size = ilogb(bsized) + 127;
#endif
/* Now increase the node size until it fits for sure */
#ifdef RADSTATS
thisloops = 0;
#endif
done = 0;
while (!done)
{
test_id.Size = base_id.Size;
for (idx = 0; idx < 2 && !done; idx++)
{
for (idy = 0; idy < 2 && !done; idy++)
{
for (idz = 0; idz < 2 && !done; idz++)
{
test_id.x = base_id.x + idx;
test_id.y = base_id.y + idy;
test_id.z = base_id.z + idz;
if (ot_point_in_node(min_point, &test_id) &&
ot_point_in_node(max_point, &test_id))
{
done = 1;
}
}
}
}
/*
* Debug_Info("looping %d,%d,%d,%d min=%d, max=%d\n", test_id.x,
* test_id.y,test_id.z, test_id.Size, ot_point_in_node(min_point,
* &test_id), ot_point_in_node(max_point, &test_id));
*/
ot_parent(&base_id, &base_id);
#ifdef RADSTATS
totloops++;
thisloops++;
#endif
}
#ifdef RADSTATS
if (thisloops < minloops)
minloops = thisloops;
if (thisloops > maxloops)
maxloops = thisloops;
#endif
*id = test_id;
#ifdef OT_DEBUG
if (id->Size > 139)
{
Debug_Info("unusually large id, maxdel=%.4f, bsized=%.4f, isize=%d\n",
maxdel, bsized, id->Size);
}
#endif
}
____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde
Visit POV-Ray on the web: http://mac.povray.org
Post a reply to this message
|
|