Esempio n. 1
0
void Post_Tnormal (TNORMAL *Tnormal)
{
	int i;
	BLEND_MAP *Map;

	if (Tnormal != NULL)
	{
		if (Tnormal->Flags & POST_DONE)
		{
			return;
		}

		if (Tnormal->Type == NO_PATTERN)
		{
			throw POV_EXCEPTION_STRING("No normal type given.");
		}

		Tnormal->Flags |= POST_DONE;

		if ((Map = Tnormal->Blend_Map) != NULL)
		{
			for (i = 0; i < Map->Number_Of_Entries; i++)
			{
				switch (Map->Type)
				{
					case PIGMENT_TYPE:

						Post_Pigment(Map->Blend_Map_Entries[i].Vals.Pigment);

						break;

					case NORMAL_TYPE:
						Map->Blend_Map_Entries[i].Vals.Tnormal->Flags |=
							(Tnormal->Flags & DONT_SCALE_BUMPS_FLAG);

						Post_Tnormal(Map->Blend_Map_Entries[i].Vals.Tnormal);

						break;

					case TEXTURE_TYPE:

						Post_Textures(Map->Blend_Map_Entries[i].Vals.Texture);

						break;

					case SLOPE_TYPE:
					case COLOUR_TYPE:
					case PATTERN_TYPE:

						break;

					default:

						throw POV_EXCEPTION_STRING("Unknown pattern type in Post_Tnormal.");
				}
			}
		}
	}
}
Esempio n. 2
0
UCS2String vfeSession::GetUCS2StringOption(const char *OptionName, const UCS2String& DefaultVal)
{
  struct ProcessOptions::INI_Parser_Table *op = GetPT(OptionName);
  if (op == NULL)
    throw POV_EXCEPTION_STRING("Invalid option");
  if (m_OptionsSet == false)
    throw POV_EXCEPTION_STRING("Options not set");

  return m_RenderOptions.m_Options.TryGetUCS2String(op->key, DefaultVal);
}
Esempio n. 3
0
bool vfeSession::OptionPresent(const char *OptionName)
{
  struct ProcessOptions::INI_Parser_Table *op = GetPT(OptionName);
  if (op == NULL)
    throw POV_EXCEPTION_STRING("Invalid option");

  if (m_OptionsSet == false)
    throw POV_EXCEPTION_STRING("Options not set");

  return m_RenderOptions.m_Options.Exist(op->key);
}
Esempio n. 4
0
void PhotonSortingTask::Run()
{
    // quit right away if photons not enabled
    if (!GetSceneData()->photonSettings.photonsEnabled) return;

    Cooperate();

    if(strategy!=NULL)
    {
        delete strategy;
        sortPhotonMap();
    }
    else
    {
        if (!this->load())
            messageFactory.Error(POV_EXCEPTION_STRING("Failed to load photon map from disk"), "Could not load photon map (%s)",GetSceneData()->photonSettings.fileName);

        // set photon options automatically
        if (GetSceneData()->surfacePhotonMap.numPhotons>0)
            GetSceneData()->surfacePhotonMap.setGatherOptions(GetSceneData()->photonSettings,false);
        if (GetSceneData()->mediaPhotonMap.numPhotons>0)
            GetSceneData()->mediaPhotonMap.setGatherOptions(GetSceneData()->photonSettings,true);
    }

    // good idea to make sure all warnings and errors arrive frontend now [trf]
    SendProgress();
    Cooperate();
}
Esempio n. 5
0
void Cone::Compute_Cylinder_Data()
{
    DBL tmpf;
    Vector3d axis;

    axis = apex - base;

    tmpf = axis.length();

    if (tmpf < EPSILON)
    {
        throw POV_EXCEPTION_STRING("Degenerate cylinder, base point = apex point."); // TODO FIXME - should a possible error
    }
    else
    {
        axis /= tmpf;

        Compute_Coordinate_Transform(Trans, base, axis, apex_radius, tmpf);
    }

    dist = 0.0;

    /* Recalculate the bounds */

    Compute_BBox();
}
Esempio n. 6
0
void MSquareQuad(UV_VECT st[4], DBL sq[3][3])
{
	DBL sx, sy, dx1, dx2, dy1, dy2, det;

	dx1 = st[1][0] - st[2][0];
	dx2 = st[3][0] - st[2][0];
	dy1 = st[1][1] - st[2][1];
	dy2 = st[3][1] - st[2][1];

	sx = st[0][0] - st[1][0] + st[2][0] - st[3][0];
	sy = st[0][1] - st[1][1] + st[2][1] - st[3][1];

	det = Det(dx1, dx2, dy1, dy2);

	if(det == 0.0)
	{
		throw POV_EXCEPTION_STRING("Equal uv-vectors detected, division by zero!");
	}

	sq[0][2] = Det(sx, dx2, sy, dy2)/det;
	sq[1][2] = Det(dx1, sx, dy1, sy)/det;
	sq[2][2] = 1;
	sq[0][0] = st[1][0] - st[0][0] + sq[0][2]*st[1][0];
	sq[1][0] = st[3][0] - st[0][0] + sq[1][2]*st[3][0];
	sq[2][0] = st[0][0];
	sq[0][1] = st[1][1] - st[0][1] + sq[0][2]*st[1][1];
	sq[1][1] = st[3][1] - st[0][1] + sq[1][2]*st[3][1];
	sq[2][1] = st[0][1];
}
Esempio n. 7
0
static void waves (const Vector3d& EPoint, const TNORMAL *Tnormal, Vector3d& normal, const TraceThreadData *Thread)
{
    register unsigned int i;
    register DBL length, scalar, index, sinValue;
    Vector3d point;

    WavesPattern* pPat = dynamic_cast<WavesPattern*>(Tnormal->pattern.get());
    if (pPat == NULL)
        throw POV_EXCEPTION_STRING("Invalid pattern type.");

    for (i = 0; i < Thread->numberOfWaves; i++)
    {
        point = EPoint - Thread->waveSources[i];

        length = point.length();

        if (length == 0.0)
        {
            length = 1.0;
        }

        index = length * pPat->waveFrequency * Thread->waveFrequencies[i] + pPat->wavePhase;

        sinValue = cycloidal(index);

        scalar = sinValue * Tnormal->Amount / Thread->waveFrequencies[i];

        normal += (scalar / (length * (DBL)Thread->numberOfWaves)) * point;
    }
}
Esempio n. 8
0
void Acquire_Spline_Reference(SPLINE * Spline)
{
    if (Spline)
    {
        if (Spline->ref_count >= INT_MAX)
            throw POV_EXCEPTION_STRING("Too many unresolved references to single spline\n");
        Spline->ref_count ++;
    }
}
Esempio n. 9
0
DBL chdtri(DBL df, DBL  y)
{
    DBL x;

    if ((y < 0.0) || (y > 1.0) || (df < 1.0))
        throw POV_EXCEPTION_STRING("Illegal values in chdtri().");

    x = igami(0.5 * df, y);

    return (2.0 * x);
}
Esempio n. 10
0
void Destroy_Spline(SPLINE * Spline)
{
    if (Spline->ref_count <= 0)
        throw POV_EXCEPTION_STRING("Internal error: Invalid spline reference count\n");

    Spline->ref_count --;
    if (Spline->ref_count == 0)
    {
        POV_FREE(Spline->SplineEntries);
        POV_FREE(Spline);
    }
}
Esempio n. 11
0
FractalRulesPtr RulesDispatch::CreateNew(const FractalConstructorData& data)
{
    std::map<FractalFuncType, const RulesDispatch *>::const_iterator dispatchIter;
    dispatchIter = DispatchMap().find(data.funcType);
    if (dispatchIter == DispatchMap().end())
    {
        DumpDispatchMap(DispatchMap());
        throw POV_EXCEPTION_STRING("Algebra/function type/variant combination unknown in fractal.");
    }
    else
        return (*(dispatchIter->second->mCreatorFunc))(data);
}
Esempio n. 12
0
void Parametric::Precompute_Parametric_Values(char flags, int depth, FPUContext *ctx)
{
	DBL * Last;
	char* es = "precompute";
	int nmb;

	if ((depth < 1) || (depth > 20))
		throw POV_EXCEPTION_STRING("Precompute: invalid depth");
	nmb = 1 << depth;

	PData = (PRECOMP_PAR_DATA *)POV_MALLOC(sizeof(PRECOMP_PAR_DATA), es);
	if (PData == NULL)
		throw POV_EXCEPTION_STRING("Cannot allocate memory for parametric precomputation data.");
	PData->flags = flags;
	PData->depth = depth;
	PData->use = 1;

	if (flags & OK_X)
	{
		PData->Low[0] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
		Last = PData->Hi[0] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
	}
	if (flags & OK_Y)
	{
		PData->Low[1] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
		Last = PData->Hi[1] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
	}
	if (flags & OK_Z)
	{
		PData->Low[2] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
		Last = PData->Hi[2] = (DBL *)POV_MALLOC(sizeof(DBL) * nmb, es);
	}
	if (Last == NULL)
		throw POV_EXCEPTION_STRING("Cannot allocate memory for parametric precomputation data.");

	PrecompLastDepth = 1 << (depth - 1);
	Precomp_Par_Int(1, umin, vmin, umax, vmax, ctx);
}
Esempio n. 13
0
DitherHandlerPtr GetDitherHandler(int method, unsigned int imageWidth)
{
	switch (method)
	{
		case kPOVList_DitherMethod_None:            return DitherHandlerPtr(new NoDither());
		case kPOVList_DitherMethod_Diffusion1D:     return DitherHandlerPtr(new DiffusionDither1D());
		case kPOVList_DitherMethod_Diffusion2D:     return DitherHandlerPtr(new DiffusionDither2D(imageWidth));
		case kPOVList_DitherMethod_FloydSteinberg:  return DitherHandlerPtr(new FloydSteinbergDither(imageWidth));
		case kPOVList_DitherMethod_Bayer2x2:        return DitherHandlerPtr(new BayerDither(2));
		case kPOVList_DitherMethod_Bayer3x3:        return DitherHandlerPtr(new BayerDither(3));
		case kPOVList_DitherMethod_Bayer4x4:        return DitherHandlerPtr(new BayerDither(4));
		default:                                    throw POV_EXCEPTION_STRING("Invalid dither method for output");
	}
}
Esempio n. 14
0
void MInvers(MATRIX r, const MATRIX  m)
{
	DBL d00, d01, d02, d03;
	DBL d10, d11, d12, d13;
	DBL d20, d21, d22, d23;
	DBL d30, d31, d32, d33;
	DBL m00, m01, m02, m03;
	DBL m10, m11, m12, m13;
	DBL m20, m21, m22, m23;
	DBL m30, m31, m32, m33;
	DBL D;

	m00 = m[0][0];  m01 = m[0][1];  m02 = m[0][2];  m03 = m[0][3];
	m10 = m[1][0];  m11 = m[1][1];  m12 = m[1][2];  m13 = m[1][3];
	m20 = m[2][0];  m21 = m[2][1];  m22 = m[2][2];  m23 = m[2][3];
	m30 = m[3][0];  m31 = m[3][1];  m32 = m[3][2];  m33 = m[3][3];

	d00 = m11*m22*m33 + m12*m23*m31 + m13*m21*m32 - m31*m22*m13 - m32*m23*m11 - m33*m21*m12;
	d01 = m10*m22*m33 + m12*m23*m30 + m13*m20*m32 - m30*m22*m13 - m32*m23*m10 - m33*m20*m12;
	d02 = m10*m21*m33 + m11*m23*m30 + m13*m20*m31 - m30*m21*m13 - m31*m23*m10 - m33*m20*m11;
	d03 = m10*m21*m32 + m11*m22*m30 + m12*m20*m31 - m30*m21*m12 - m31*m22*m10 - m32*m20*m11;

	d10 = m01*m22*m33 + m02*m23*m31 + m03*m21*m32 - m31*m22*m03 - m32*m23*m01 - m33*m21*m02;
	d11 = m00*m22*m33 + m02*m23*m30 + m03*m20*m32 - m30*m22*m03 - m32*m23*m00 - m33*m20*m02;
	d12 = m00*m21*m33 + m01*m23*m30 + m03*m20*m31 - m30*m21*m03 - m31*m23*m00 - m33*m20*m01;
	d13 = m00*m21*m32 + m01*m22*m30 + m02*m20*m31 - m30*m21*m02 - m31*m22*m00 - m32*m20*m01;

	d20 = m01*m12*m33 + m02*m13*m31 + m03*m11*m32 - m31*m12*m03 - m32*m13*m01 - m33*m11*m02;
	d21 = m00*m12*m33 + m02*m13*m30 + m03*m10*m32 - m30*m12*m03 - m32*m13*m00 - m33*m10*m02;
	d22 = m00*m11*m33 + m01*m13*m30 + m03*m10*m31 - m30*m11*m03 - m31*m13*m00 - m33*m10*m01;
	d23 = m00*m11*m32 + m01*m12*m30 + m02*m10*m31 - m30*m11*m02 - m31*m12*m00 - m32*m10*m01;

	d30 = m01*m12*m23 + m02*m13*m21 + m03*m11*m22 - m21*m12*m03 - m22*m13*m01 - m23*m11*m02;
	d31 = m00*m12*m23 + m02*m13*m20 + m03*m10*m22 - m20*m12*m03 - m22*m13*m00 - m23*m10*m02;
	d32 = m00*m11*m23 + m01*m13*m20 + m03*m10*m21 - m20*m11*m03 - m21*m13*m00 - m23*m10*m01;
	d33 = m00*m11*m22 + m01*m12*m20 + m02*m10*m21 - m20*m11*m02 - m21*m12*m00 - m22*m10*m01;

	D = m00*d00 - m01*d01 + m02*d02 - m03*d03;

	if (D == 0.0)
	{
		throw POV_EXCEPTION_STRING("Singular matrix in MInvers.");
	}

	r[0][0] =  d00/D; r[0][1] = -d10/D;  r[0][2] =  d20/D; r[0][3] = -d30/D;
	r[1][0] = -d01/D; r[1][1] =  d11/D;  r[1][2] = -d21/D; r[1][3] =  d31/D;
	r[2][0] =  d02/D; r[2][1] = -d12/D;  r[2][2] =  d22/D; r[2][3] = -d32/D;
	r[3][0] = -d03/D; r[3][1] =  d13/D;  r[3][2] = -d23/D; r[3][3] =  d33/D;
}
Esempio n. 15
0
bool BicubicPatch::All_Intersections(const Ray& ray, IStack& Depth_Stack, TraceThreadData *Thread)
{
    int Found, cnt = 0;

    Found = false;

    Thread->Stats()[Ray_Bicubic_Tests]++;

    switch (Patch_Type)
    {
        case 0:

            cnt = intersect_bicubic_patch0(ray, Depth_Stack, Thread);

            break;

        case 1:

            cnt = bezier_tree_walker(ray, Node_Tree, Depth_Stack, Thread);

            break;

        default:

            throw POV_EXCEPTION_STRING("Bad patch type in All_Bicubic_Patch_Intersections.");
    }

    if (cnt > 0)
    {
        Thread->Stats()[Ray_Bicubic_Tests_Succeeded]++;

        Found = true;
    }

    return (Found);
}
Esempio n. 16
0
void Post_Tnormal (TNORMAL *Tnormal)
{
    GenericNormalBlendMapPtr Map;

    if (Tnormal != NULL)
    {
        if (Tnormal->Flags & POST_DONE)
        {
            return;
        }

        if (Tnormal->Type == NO_PATTERN)
        {
            throw POV_EXCEPTION_STRING("No normal type given.");
        }

        Tnormal->Flags |= POST_DONE;

        if ((Map = Tnormal->Blend_Map) != NULL)
        {
            Map->Post((Tnormal->Flags & DONT_SCALE_BUMPS_FLAG) != 0);
        }
    }
}
Esempio n. 17
0
bool Compute_Pigment (Colour& colour, const PIGMENT *Pigment, const VECTOR EPoint, const Intersection *Intersect, const Ray *ray, TraceThreadData *Thread)
{
	int Colour_Found;
	VECTOR TPoint;
	DBL value;
	register DBL fraction;
	const BLEND_MAP_ENTRY *Cur, *Prev;
	Colour Temp_Colour;
	const BLEND_MAP *Blend_Map = Pigment->Blend_Map;
	UV_VECT UV_Coords;

	if ((Thread->qualityFlags & Q_QUICKC) != 0 && Pigment->Quick_Colour[pRED] != -1.0 && Pigment->Quick_Colour[pGREEN] != -1.0 && Pigment->Quick_Colour[pBLUE] != -1.0)
	{
		colour = Pigment->Quick_Colour;
		return (true);
	}

	if (Pigment->Type <= LAST_SPECIAL_PATTERN)
	{
		Colour_Found = true;

		switch (Pigment->Type)
		{
			case NO_PATTERN:

				colour.clear();

				break;

			case PLAIN_PATTERN:

				colour = Pigment->colour;

				break;

			case AVERAGE_PATTERN:

				Warp_EPoint (TPoint, EPoint, reinterpret_cast<const TPATTERN *>(Pigment));

				Do_Average_Pigments(colour, Pigment, TPoint, Intersect, ray, Thread);

				break;

			case UV_MAP_PATTERN:
				if(Intersect == NULL)
					throw POV_EXCEPTION_STRING("The 'uv_mapping' pattern cannot be used as part of a pigment function!");

				Cur = &(Pigment->Blend_Map->Blend_Map_Entries[0]);

				if (Blend_Map->Type == COLOUR_TYPE)
				{
					Colour_Found = true;

					Assign_Colour(*colour, Cur->Vals.colour);
				}
				else
				{
					/* Don't bother warping, simply get the UV vect of the intersection */
					Intersect->Object->UVCoord(UV_Coords, Intersect, Thread);
					TPoint[X] = UV_Coords[U];
					TPoint[Y] = UV_Coords[V];
					TPoint[Z] = 0;

					if (Compute_Pigment(colour, Cur->Vals.Pigment,TPoint,Intersect, ray, Thread))
						Colour_Found = true;
				}

				break;

			case BITMAP_PATTERN:

				Warp_EPoint (TPoint, EPoint, reinterpret_cast<const TPATTERN *>(Pigment));

				colour.clear();

				Colour_Found = image_map (TPoint, Pigment, colour);

				break;

			default:

				throw POV_EXCEPTION_STRING("Pigment type not yet implemented.");
		}

		return(Colour_Found);
	}

	Colour_Found = false;

	/* NK 19 Nov 1999 added Warp_EPoint */
	Warp_EPoint (TPoint, EPoint, reinterpret_cast<const TPATTERN *>(Pigment));
	value = Evaluate_TPat (reinterpret_cast<const TPATTERN *>(Pigment),TPoint,Intersect, ray, Thread);

	Search_Blend_Map (value, Blend_Map, &Prev, &Cur);

	if (Blend_Map->Type == COLOUR_TYPE)
	{
		Colour_Found = true;

		Assign_Colour(*colour, Cur->Vals.colour);
	}
	else
	{
		Warp_EPoint (TPoint, EPoint, reinterpret_cast<const TPATTERN *>(Pigment));

		if (Compute_Pigment(colour, Cur->Vals.Pigment,TPoint,Intersect, ray, Thread))
			Colour_Found = true;
	}

	if (Prev != Cur)
	{
		if (Blend_Map->Type == COLOUR_TYPE)
		{
			Colour_Found = true;

			Assign_Colour(*Temp_Colour, Prev->Vals.colour);
		}
		else
		{
			if (Compute_Pigment(Temp_Colour, Prev->Vals.Pigment, TPoint, Intersect, ray, Thread))
				Colour_Found = true;
		}

		fraction = (value - Prev->value) / (Cur->value - Prev->value);

		colour = Temp_Colour + fraction * (colour - Temp_Colour);
	}

	return(Colour_Found);
}
Esempio n. 18
0
int Post_Pigment(PIGMENT *Pigment)
{
	int i, Has_Filter;
	BLEND_MAP *Map;

	if (Pigment == NULL)
	{
		throw POV_EXCEPTION_STRING("Missing pigment");
	}

	if (Pigment->Flags & POST_DONE)
	{
		return(Pigment->Flags & HAS_FILTER);
	}

	if (Pigment->Type == NO_PATTERN)
	{
		Pigment->Type = PLAIN_PATTERN;

		Pigment->colour.clear() ;

;// TODO MESSAGE    Warning(150, "No pigment type given.");
	}

	Pigment->Flags |= POST_DONE;

	switch (Pigment->Type)
	{
		case PLAIN_PATTERN:

			Destroy_Warps (Pigment->Warps);

			Pigment->Warps = NULL;

			break;

		case NO_PATTERN:
		case BITMAP_PATTERN:

			break;

		default:

			if (Pigment->Blend_Map == NULL)
			{
				switch (Pigment->Type)
				{
					// NB: The const default blend maps are marked so that they will not be modified nor destroyed later.
					case BOZO_PATTERN:    Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Bozo_Default_Map);  break;
					case BRICK_PATTERN:   Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Brick_Default_Map); break;
					case WOOD_PATTERN:    Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Wood_Default_Map);  break;
					case MANDEL_PATTERN:  Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Mandel_Default_Map);break;
					case RADIAL_PATTERN:  Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Radial_Default_Map);break;
					case AGATE_PATTERN:   Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Agate_Default_Map); break;
					case MARBLE_PATTERN:  Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Marble_Default_Map);break;
					case HEXAGON_PATTERN: Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Hex_Default_Map);   break;
					case SQUARE_PATTERN:  Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Square_Default_Map);break;
					case TRIANGULAR_PATTERN: Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Triangular_Default_Map);break;
					case CUBIC_PATTERN:   Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Cubic_Default_Map); break; // JN2007: Cubic pattern
					case CHECKER_PATTERN: Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Check_Default_Map); break;
					case AVERAGE_PATTERN: break;// TODO MESSAGE Error("Missing pigment_map in average pigment"); break;
					case OBJECT_PATTERN:  Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Check_Default_Map); break;
					default:              Pigment->Blend_Map = const_cast<BLEND_MAP *>(&Gray_Default_Map);  break;
				}
			}

			break;
	}

	/* Now we test wether this pigment is opaque or not. [DB 8/94] */

	Has_Filter = false;

	if ((fabs(Pigment->colour[pFILTER]) > EPSILON) ||
	    (fabs(Pigment->colour[pTRANSM]) > EPSILON))
	{
		Has_Filter = true;
	}

	if ((Pigment->Type == BITMAP_PATTERN) &&
	    (Pigment->Vals.image != NULL))
	{
		// bitmaps are transparent if they are used only once, or the image is not opaque
		Has_Filter |= (Pigment->Vals.image->Once_Flag) || !is_image_opaque(Pigment->Vals.image);
	}

	if ((Map = Pigment->Blend_Map) != NULL)
	{
		if ((Map->Type == PIGMENT_TYPE) || (Map->Type == DENSITY_TYPE))
		{
			for (i = 0; i < Map->Number_Of_Entries; i++)
			{
				Has_Filter |= Post_Pigment(Map->Blend_Map_Entries[i].Vals.Pigment);
			}
		}
		else
		{
			for (i = 0; i < Map->Number_Of_Entries; i++)
			{
				Has_Filter |= fabs(Map->Blend_Map_Entries[i].Vals.colour[pFILTER])>EPSILON;
				Has_Filter |= fabs(Map->Blend_Map_Entries[i].Vals.colour[pTRANSM])>EPSILON;
			}
		}
	}

	if (Has_Filter)
	{
		Pigment->Flags |= HAS_FILTER;
	}

	if (Pigment->Next != NULL)
	{
		Post_Pigment(reinterpret_cast<PIGMENT *>(Pigment->Next));
	}

	return(Has_Filter);
}
Esempio n. 19
0
void Perturb_Normal(VECTOR Layer_Normal, const TNORMAL *Tnormal, const VECTOR EPoint, Intersection *Intersection, const Ray *ray, TraceThreadData *Thread)
{
	VECTOR TPoint,P1;
	DBL value1,value2,Amount;
	int i;
	BLEND_MAP *Blend_Map;
	BLEND_MAP_ENTRY *Prev, *Cur;

	if (Tnormal==NULL)
	{
		return;
	}

	/* If normal_map present, use it and return */

	if ((Blend_Map=Tnormal->Blend_Map) != NULL)
	{
		if ((Blend_Map->Type == NORMAL_TYPE) && (Tnormal->Type == UV_MAP_PATTERN))
		{
			UV_VECT UV_Coords;

			Cur = &(Tnormal->Blend_Map->Blend_Map_Entries[0]);

			/* Don't bother warping, simply get the UV vect of the intersection */
			Intersection->Object->UVCoord(UV_Coords, Intersection, Thread);
			TPoint[X] = UV_Coords[U];
			TPoint[Y] = UV_Coords[V];
			TPoint[Z] = 0;

			Perturb_Normal(Layer_Normal,Cur->Vals.Tnormal,TPoint,Intersection,ray,Thread);
			VNormalizeEq(Layer_Normal);
			Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */

			return;
		}
		else if ((Blend_Map->Type == NORMAL_TYPE) && (Tnormal->Type != AVERAGE_PATTERN))
		{
			/* NK 19 Nov 1999 added Warp_EPoint */
			Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);
			value1 = Evaluate_TPat((TPATTERN *)Tnormal,TPoint,Intersection,ray,Thread);

			Search_Blend_Map (value1,Blend_Map,&Prev,&Cur);

			Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
			Assign_Vector(P1,Layer_Normal);

			Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);

			Perturb_Normal(Layer_Normal,Cur->Vals.Tnormal,TPoint,Intersection,ray,Thread);

			if (Prev != Cur)
			{
				Perturb_Normal(P1,Prev->Vals.Tnormal,TPoint,Intersection,ray,Thread);

				value2 = (value1-Prev->value)/(Cur->value-Prev->value);
				value1 = 1.0-value2;

				VLinComb2(Layer_Normal,value1,P1,value2,Layer_Normal);
			}

			UnWarp_Normal(Layer_Normal,Layer_Normal,(TPATTERN *)Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

			VNormalizeEq(Layer_Normal);

			Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */

			return;
		}
	}

	/* No normal_map. */

	if (Tnormal->Type <= LAST_NORM_ONLY_PATTERN)
	{
		Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
		            Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

		Warp_EPoint (TPoint, EPoint, (TPATTERN *)Tnormal);

		switch (Tnormal->Type)
		{
			case BITMAP_PATTERN:    bump_map    (TPoint, Tnormal, Layer_Normal);            break;
			case BUMPS_PATTERN:     bumps       (TPoint, Tnormal, Layer_Normal);            break;
			case DENTS_PATTERN:     dents       (TPoint, Tnormal, Layer_Normal, Thread);    break;
			case RIPPLES_PATTERN:   ripples     (TPoint, Tnormal, Layer_Normal, Thread);    break;
			case WAVES_PATTERN:     waves       (TPoint, Tnormal, Layer_Normal, Thread);    break;
			case WRINKLES_PATTERN:  wrinkles    (TPoint, Tnormal, Layer_Normal);            break;
			case QUILTED_PATTERN:   quilted     (TPoint, Tnormal, Layer_Normal);            break;
			case FACETS_PATTERN:    facets      (TPoint, Tnormal, Layer_Normal, Thread);    break;
			case AVERAGE_PATTERN:   Do_Average_Normals (TPoint, Tnormal, Layer_Normal, Intersection, ray, Thread); break;
			default:
				throw POV_EXCEPTION_STRING("Normal pattern not yet implemented.");
		}

		UnWarp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
		              Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
	}
	else
	{
		Warp_Normal(Layer_Normal,Layer_Normal, (TPATTERN *)Tnormal,
		            Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

		Amount=Tnormal->Amount * -5.0; /*fudge factor*/
		Amount*=0.02/Tnormal->Delta; /* NK delta */

		/* warp the center point first - this is the last warp */
		Warp_EPoint(TPoint,EPoint,(TPATTERN *)Tnormal);

		for(i=0; i<=3; i++)
		{
			VAddScaled(P1,TPoint,Tnormal->Delta,Pyramid_Vect[i]); /* NK delta */
			value1 = Do_Slope_Map(Evaluate_TPat((TPATTERN *)Tnormal,P1,Intersection,ray,Thread),Blend_Map);
			VAddScaledEq(Layer_Normal,value1*Amount,Pyramid_Vect[i]);
		}

		UnWarp_Normal(Layer_Normal,Layer_Normal,(TPATTERN *)Tnormal,
		              Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

	}

	if ( Intersection )
		Assign_Vector(Intersection->PNormal, Layer_Normal); /* -hdf- June 98 */
}
Esempio n. 20
0
DBL AVX2FMA3Noise(const Vector3d& EPoint, int noise_generator)
{
    AVX2TABLETYPE *mp;
    DBL sum = 0.0;

    // TODO FIXME - global statistics reference
    // Stats[Calls_To_Noise]++;

    if (noise_generator == kNoiseGen_Perlin)
    {
        // The 1.59 and 0.985 are to correct for some biasing problems with
        // the random # generator used to create the noise tables.  Final
        // range of values is about 5.0e-4 below 0.0 and above 1.0.  Mean
        // value is 0.49 (ideally it would be 0.5).
        sum = 0.5 * (1.59 * SolidNoise(EPoint) + 0.985);

        // Clamp final value to 0-1 range
        if (sum < 0.0) sum = 0.0;
        if (sum > 1.0) sum = 1.0;

        return sum;
    }

    const __m256d ONE_PD = _mm256_set1_pd(1);
    const __m128i short_si128 = _mm_set1_epi32(0xffff);

    const __m256d xyzn = _mm256_setr_pd(EPoint[X], EPoint[Y], EPoint[Z], 0);
    const __m256d epsy = _mm256_set1_pd(1.0 - EPSILON);
    const __m256d xyzn_e = _mm256_sub_pd(xyzn, epsy);
    const __m128i tmp_xyzn = _mm256_cvttpd_epi32(_mm256_blendv_pd(xyzn, xyzn_e, xyzn));

    const __m128i noise_min_xyzn = _mm_setr_epi32(NOISE_MINX, NOISE_MINY, NOISE_MINZ, 0);

    const __m256d xyz_ixyzn = _mm256_sub_pd(xyzn, _mm256_cvtepi32_pd(tmp_xyzn));
    const __m256d xyz_jxyzn = _mm256_sub_pd(xyz_ixyzn, ONE_PD);

    const __m128i i_xyzn = _mm_and_si128(_mm_sub_epi32(tmp_xyzn, noise_min_xyzn),
        _mm_set1_epi32(0xfff));

    const __m256d s_xyzn = _mm256_mul_pd(xyz_ixyzn,
        _mm256_mul_pd(xyz_ixyzn,
            _mm256_sub_pd(_mm256_set1_pd(3.0),
                _mm256_add_pd(xyz_ixyzn, xyz_ixyzn))));

    const __m256d t_xyzn = _mm256_sub_pd(ONE_PD, s_xyzn);

    const __m256d txtysxsy = _mm256_permute2f128_pd(t_xyzn, s_xyzn, 0x20);
    const __m256d txsxtxsx = PERMUTE4x64(txtysxsy, _MM_SHUFFLE(2, 0, 2, 0));
    const __m256d tytysysy = PERMUTE4x64(txtysxsy, _MM_SHUFFLE(3, 3, 1, 1));

    const __m256d txtysxtytxsysxsy = _mm256_mul_pd(txsxtxsx, tytysysy);

    const __m256d incrsump_s1 = _mm256_mul_pd(txtysxtytxsysxsy, PERMUTE4x64(t_xyzn, _MM_SHUFFLE(2, 2, 2, 2)));
    const __m256d incrsump_s2 = _mm256_mul_pd(txtysxtytxsysxsy, PERMUTE4x64(s_xyzn, _MM_SHUFFLE(2, 2, 2, 2)));

    int ints[4];
    _mm_storeu_si128((__m128i*)(ints), i_xyzn);

    const int ixiy_hash = Hash2d(ints[0], ints[1]);
    const int jxiy_hash = Hash2d(ints[0] + 1, ints[1]);
    const int ixjy_hash = Hash2d(ints[0], ints[1] + 1);
    const int jxjy_hash = Hash2d(ints[0] + 1, ints[1] + 1);

    const int iz = ints[2];

    const __m256d iii = _mm256_blend_pd(PERMUTE4x64(xyz_ixyzn, _MM_SHUFFLE(2, 1, 0, 0)), _mm256_set_pd(0, 0, 0, 0.5), 0x1);
    const __m256d jjj = _mm256_blend_pd(PERMUTE4x64(xyz_jxyzn, _MM_SHUFFLE(2, 1, 0, 0)), _mm256_set_pd(0, 0, 0, 0.5), 0x1);

    __m256d sumr = _mm256_setzero_pd();
    __m256d sumr1 = _mm256_setzero_pd();


    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixiy_hash, iz)];
    INCSUMAVX_NOBLEND(sumr, mp, PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(0, 0, 0, 0)), iii);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxiy_hash, iz)];
    INCSUMAVX(sumr1, mp, PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(1, 1, 1, 1)), iii, jjj, 2);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixjy_hash, iz)];
    INCSUMAVX(sumr, mp, PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(2, 2, 2, 2)), iii, jjj, 4);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxjy_hash, iz)];
    INCSUMAVX(sumr1, mp, PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(3, 3, 3, 3)), iii, jjj, 6);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixiy_hash, iz + 1)];
    INCSUMAVX(sumr, mp, PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(0, 0, 0, 0)), iii, jjj, 8);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxiy_hash, iz + 1)];
    INCSUMAVX(sumr1, mp, PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(1, 1, 1, 1)), iii, jjj, 10);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixjy_hash, iz + 1)];
    INCSUMAVX(sumr, mp, PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(2, 2, 2, 2)), iii, jjj, 12);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxjy_hash, iz + 1)];
    INCSUMAVX_NOBLEND(sumr1, mp, PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(3, 3, 3, 3)), jjj);

    {
        sumr = _mm256_add_pd(sumr, sumr1);

        __m128d sumr_up = _mm256_extractf128_pd(sumr,1);
        sumr_up = _mm_add_pd(_mm256_castpd256_pd128(sumr),sumr_up);
        sumr_up = _mm_hadd_pd(sumr_up,sumr_up);
        sum = _mm_cvtsd_f64(sumr_up);
    }

    if (noise_generator == kNoiseGen_RangeCorrected)
    {
        /* details of range here:
        Min, max: -1.05242, 0.988997
        Mean: -0.0191481, Median: -0.535493, Std Dev: 0.256828

        We want to change it to as close to [0,1] as possible.
        */
        sum += 1.05242;
        sum *= 0.48985582;
        /*sum *= 0.5;
        sum += 0.5;*/

        if (sum < 0.0)
            sum = 0.0;
        if (sum > 1.0)
            sum = 1.0;
    }
    else
    {
        sum = sum + 0.5;                     /* range at this point -0.5 - 0.5... */

        if (sum < 0.0)
            sum = 0.0;
        if (sum > 1.0)
            sum = 1.0;
    }



#if CHECK_FUNCTIONAL
    {
        DBL orig_sum = PortableNoise(EPoint, noise_generator);
        if (fabs(orig_sum - sum) >= EPSILON)
        {
            throw POV_EXCEPTION_STRING("Noise error");
        }

    }

#endif

    _mm256_zeroupper();
    return (sum);
}
Esempio n. 21
0
int Fractal::SetUp_Fractal(void)
{
    switch (Algebra)
    {
        case QUATERNION_TYPE:

            switch(Sub_Type)
            {
                case CUBE_STYPE:
                    Rules = FractalRulesPtr(new Z3FractalRules());
                    break;
                case SQR_STYPE:
                    Rules = FractalRulesPtr(new JuliaFractalRules());
                    break;
                default:
                    throw POV_EXCEPTION_STRING("Illegal function: quaternion only supports sqr and cube");
            }

            break;

        case HYPERCOMPLEX_TYPE:

            switch (Sub_Type)
            {
                case RECIPROCAL_STYPE:

                    Rules = FractalRulesPtr(new HypercomplexReciprocalFractalRules());
                    break;

                case EXP_STYPE:
                case LN_STYPE:
                case SIN_STYPE:
                case ASIN_STYPE:
                case COS_STYPE:
                case ACOS_STYPE:
                case TAN_STYPE:
                case ATAN_STYPE:
                case SINH_STYPE:
                case ASINH_STYPE:
                case COSH_STYPE:
                case ACOSH_STYPE:
                case TANH_STYPE:
                case ATANH_STYPE:
                case PWR_STYPE:

                    Rules = FractalRulesPtr(new HypercomplexFunctionFractalRules(Complex_Function_List[Sub_Type]));
                    break;

                case CUBE_STYPE:

                    Rules = FractalRulesPtr(new HypercomplexZ3FractalRules());
                    break;

                default:  /* SQR_STYPE or else... */

                    Rules = FractalRulesPtr(new HypercomplexFractalRules());
                    break;
            }

            break;

        default:

            throw POV_EXCEPTION_STRING("Algebra unknown in fractal.");
    }

    Compute_BBox();

    return Num_Iterations;
}
Esempio n. 22
0
void Polygon::Compute_Polygon(int number, Vector3d *points)
{
    int i;
    DBL x, y, z, d;
    Vector3d o, u, v, w, N;
    MATRIX a, b;

    /* Create polygon data. */

    if (Data == NULL)
    {
        Data = reinterpret_cast<POLYGON_DATA *>(POV_MALLOC(sizeof(POLYGON_DATA), "polygon points"));

        Data->References = 1;

        Data->Number = number;

        Data->Points = reinterpret_cast<Vector2d *>(POV_MALLOC(number*sizeof(Vector2d), "polygon points"));
    }
    else
    {
        throw POV_EXCEPTION_STRING("Polygon data already computed.");
    }

    /* Get polygon's coordinate system (one of the many possible) */

    o = points[0];

    /* Find valid, i.e. non-zero u vector. */

    for (i = 1; i < number; i++)
    {
        u = points[i] - o;

        if (u.lengthSqr() > EPSILON)
        {
            break;
        }
    }

    if (i == number)
    {
        Set_Flag(this, DEGENERATE_FLAG);

;// TODO MESSAGE    Warning("Points in polygon are co-linear. Ignoring polygon.");
    }

    /* Find valid, i.e. non-zero v and w vectors. */

    for (i++; i < number; i++)
    {
        v = points[i] - o;

        w = cross(u, v);

        if ((v.lengthSqr() > EPSILON) && (w.lengthSqr() > EPSILON))
        {
            break;
        }
    }

    if (i == number)
    {
        Set_Flag(this, DEGENERATE_FLAG);

;// TODO MESSAGE    Warning("Points in polygon are co-linear. Ignoring polygon.");
    }

    u = cross(v, w);
    v = cross(w, u);

    u.normalize();
    v.normalize();
    w.normalize();

    MIdentity(a);
    MIdentity(b);

    a[3][0] = -o[X];
    a[3][1] = -o[Y];
    a[3][2] = -o[Z];

    b[0][0] =  u[X];
    b[1][0] =  u[Y];
    b[2][0] =  u[Z];

    b[0][1] =  v[X];
    b[1][1] =  v[Y];
    b[2][1] =  v[Z];

    b[0][2] =  w[X];
    b[1][2] =  w[Y];
    b[2][2] =  w[Z];

    MTimesC(Trans->inverse, a, b);

    MInvers(Trans->matrix, Trans->inverse);

    /* Project points onto the u,v-plane (3D --> 2D) */

    for (i = 0; i < number; i++)
    {
        x = points[i][X] - o[X];
        y = points[i][Y] - o[Y];
        z = points[i][Z] - o[Z];

        d = x * w[X] + y * w[Y] + z * w[Z];

        if (fabs(d) > ZERO_TOLERANCE)
        {
            Set_Flag(this, DEGENERATE_FLAG);

;// TODO MESSAGE      Warning("Points in polygon are not co-planar. Ignoring polygons.");
        }

        Data->Points[i][X] = x * u[X] + y * u[Y] + z * u[Z];
        Data->Points[i][Y] = x * v[X] + y * v[Y] + z * v[Z];
    }

    N = Vector3d(0.0, 0.0, 1.0);
    MTransNormal(S_Normal, N, Trans);

    S_Normal.normalize();

    Compute_BBox();
}
Esempio n. 23
0
void Lemon::Compute_Lemon_Data(GenericMessenger& messenger, pov_base::ITextStream *FileHandle, pov_base::ITextStream::FilePos & Token_File_Pos, int Token_Col_No )
{
    DBL len;
    Vector3d axis;

    /* Process the primitive specific information */

    /* Find the axis and axis length */

    axis = apex - base;

    len = axis.length();

    if (len < EPSILON)
    {
        throw POV_EXCEPTION_STRING("Degenerate lemon.");
    }
    else
    {
        axis /= len; //normalize
    }
    /* adjust the various radius */
    apex_radius /= len;
    base_radius /= len;
    inner_radius /= len;
    /* Determine alignment and scale */
    Compute_Coordinate_Transform(Trans, base, axis, len, len);

    /* check constraint on inner_radius before solving the system of equation to find the
     * center of the minor circle of the torus
     *
     * base is at origin (0,0)
     * apex is at (0,1)
     * let's note base_radius as a, a>=0
     * let's note apex_radius as b, b>=0
     * let's note inner_radius as r, r>=0
     * center of minor circle is at (x,y), with x<=0
     *
     * (x-a)^2 + y^2 - r^2 = 0  : minor circle must pass on circle at base
     * (x-b)^2 + (1-y)^2 - r^2 = 0 : minor circle must pass on circle at apex
     *
     * r must be equal or greater than sqrt( a^4-2a^2(b^2-1)+(b^2+1)^2 ) / 2
     *
     * then with f = sqrt((a^2-2ab+b^2-4r^2+1)/(a^2-2ab+b^2+1))
     *
     *     x = (a+b-f)/2
     *     y = (f(b-a)+1)/2
     */
    DBL low = sqrt(base_radius*base_radius*base_radius*base_radius - 2*base_radius*base_radius*(apex_radius*apex_radius-1.0)+(apex_radius*apex_radius+1.0)*(apex_radius*apex_radius+1.0))/2.0;
    if (inner_radius < low )
    {
        std::stringstream o;
        inner_radius = low;
        o << "Inner (last) radius of lemon is too small. Minimal would be "<< (inner_radius*len) << ". Value has been adjusted.";
        messenger.WarningAt(kWarningGeneral, FileHandle->name(), Token_File_Pos.lineno, Token_Col_No, FileHandle->tellg().offset,"%s",o.str().c_str());
    }

    DBL f = sqrt(-(base_radius*base_radius-2.0*base_radius*apex_radius+apex_radius*apex_radius-4.0*inner_radius*inner_radius+1.0)/(base_radius*base_radius-2.0*base_radius*apex_radius+apex_radius*apex_radius+1.0));
    /*
     * Attention: valid HorizontalPosition is negative, always (or null)
     * It is of particular importance when using with torus evaluation and normal computation
     */
    HorizontalPosition = (base_radius+apex_radius-f)/2.0;
    VerticalPosition = ((apex_radius-base_radius)*f+1.0)/2.0;
}
Esempio n. 24
0
void Path::ParsePathString(const UCS2String& p)
{
	if(POV_PARSE_PATH_STRING(p, volume, folders, file) == false)
		throw POV_EXCEPTION_STRING("Invalid path."); // TODO FIXME - properly report path string [trf]
}
Esempio n. 25
0
void AVX2FMA3DNoise(Vector3d& result, const Vector3d& EPoint)
{

#if CHECK_FUNCTIONAL
    Vector3d param(EPoint);
#endif

    AVX2TABLETYPE *mp;

    // TODO FIXME - global statistics reference
    // Stats[Calls_To_DNoise]++;

    const __m256d ONE_PD = _mm256_set1_pd(1.0);
    const __m128i short_si128 = _mm_set1_epi32(0xffff);

    const __m256d xyzn = _mm256_setr_pd(EPoint[X], EPoint[Y], EPoint[Z], 0);
    const __m256d epsy = _mm256_set1_pd(1.0 - EPSILON);
    const __m256d xyzn_e = _mm256_sub_pd(xyzn, epsy);
    const __m128i tmp_xyzn = _mm256_cvttpd_epi32(_mm256_blendv_pd(xyzn, xyzn_e, xyzn));

    const __m128i noise_min_xyzn = _mm_setr_epi32(NOISE_MINX, NOISE_MINY, NOISE_MINZ, 0);

    const __m256d xyz_ixyzn = _mm256_sub_pd(xyzn, _mm256_cvtepi32_pd(tmp_xyzn));
    const __m256d xyz_jxyzn = _mm256_sub_pd(xyz_ixyzn, ONE_PD);

    const __m128i i_xyzn = _mm_and_si128(_mm_sub_epi32(tmp_xyzn, noise_min_xyzn),
        _mm_set1_epi32(0xfff));

    const __m256d s_xyzn = _mm256_mul_pd(xyz_ixyzn,
        _mm256_mul_pd(xyz_ixyzn,
            _mm256_sub_pd(_mm256_set1_pd(3.0),
                _mm256_add_pd(xyz_ixyzn, xyz_ixyzn))));

    const __m256d t_xyzn = _mm256_sub_pd(ONE_PD, s_xyzn);

    const __m256d txtysxsy = _mm256_permute2f128_pd(t_xyzn, s_xyzn, 0x20);
    const __m256d txsxtxsx = PERMUTE4x64(txtysxsy, _MM_SHUFFLE(2, 0, 2, 0));
    const __m256d tytysysy = PERMUTE4x64(txtysxsy, _MM_SHUFFLE(3, 3, 1, 1));

    const __m256d txtysxtytxsysxsy = _mm256_mul_pd(txsxtxsx, tytysysy);

    const __m256d incrsump_s1 = _mm256_mul_pd(txtysxtytxsysxsy, PERMUTE4x64(t_xyzn, _MM_SHUFFLE(2, 2, 2, 2)));
    const __m256d incrsump_s2 = _mm256_mul_pd(txtysxtytxsysxsy, PERMUTE4x64(s_xyzn, _MM_SHUFFLE(2, 2, 2, 2)));

    int ints[4];
    _mm_storeu_si128((__m128i*)(ints), i_xyzn);

    const int ixiy_hash = Hash2d(ints[0], ints[1]);
    const int jxiy_hash = Hash2d(ints[0] + 1, ints[1]);
    const int ixjy_hash = Hash2d(ints[0], ints[1] + 1);
    const int jxjy_hash = Hash2d(ints[0] + 1, ints[1] + 1);

    const int iz = ints[2];

    const __m256d iii = _mm256_blend_pd(PERMUTE4x64(xyz_ixyzn, _MM_SHUFFLE(2, 1, 0, 0)), _mm256_set_pd(0, 0, 0, 0.5), 0x1);
    const __m256d jjj = _mm256_blend_pd(PERMUTE4x64(xyz_jxyzn, _MM_SHUFFLE(2, 1, 0, 0)), _mm256_set_pd(0, 0, 0, 0.5), 0x1);

    __m256d ss;
    __m256d blend;

    __m256d x = _mm256_setzero_pd(), y = _mm256_setzero_pd(), z = _mm256_setzero_pd();


    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixiy_hash, iz)];
    ss = PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(0, 0, 0, 0));
    //     blend = _mm256_blend_pd(iii, jjj, 0);

    INCSUMAVX_VECTOR(mp, ss, iii);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxiy_hash, iz)];
    ss = PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(1, 1, 1, 1));
    blend = _mm256_blend_pd(iii, jjj, 2);

    INCSUMAVX_VECTOR(mp, ss, blend);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxjy_hash, iz)];
    ss = PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(3, 3, 3, 3));
    blend = _mm256_blend_pd(iii, jjj, 6);

    INCSUMAVX_VECTOR(mp, ss, blend);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixjy_hash, iz)];
    ss = PERMUTE4x64(incrsump_s1, _MM_SHUFFLE(2, 2, 2, 2));
    blend = _mm256_blend_pd(iii, jjj, 4);

    INCSUMAVX_VECTOR(mp, ss, blend);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixjy_hash, iz + 1)];
    ss = PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(2, 2, 2, 2));
    blend = _mm256_blend_pd(iii, jjj, 12);

    INCSUMAVX_VECTOR(mp, ss, blend);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxjy_hash, iz + 1)];
    ss = PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(3, 3, 3, 3));
    //     blend = _mm256_blend_pd(iii, jjj, 14);

    INCSUMAVX_VECTOR(mp, ss, jjj);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(jxiy_hash, iz + 1)];
    ss = PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(1, 1, 1, 1));
    blend = _mm256_blend_pd(iii, jjj, 10);

    INCSUMAVX_VECTOR(mp, ss, blend);

    mp = &AVX2RTable[Hash1dRTableIndexAVX(ixiy_hash, iz + 1)];
    ss = PERMUTE4x64(incrsump_s2, _MM_SHUFFLE(0, 0, 0, 0));
    blend = _mm256_blend_pd(iii, jjj, 8);

    INCSUMAVX_VECTOR(mp, ss, blend);


    __m256d xy = _mm256_hadd_pd(x,y);
    __m128d xy_up = _mm256_extractf128_pd(xy,1);
    xy_up = _mm_add_pd(_mm256_castpd256_pd128(xy),xy_up);
    _mm_storeu_pd(&result[X],xy_up);

    __m128d z_up = _mm256_extractf128_pd(z,1);
    z_up = _mm_add_pd(_mm256_castpd256_pd128(z),z_up);
    z_up = _mm_hadd_pd(z_up,z_up);
    result[Z] = _mm_cvtsd_f64(z_up);


#if CHECK_FUNCTIONAL
    {
        Vector3d portable_res;
        PortableDNoise(portable_res , param);
        if (fabs(portable_res[X] - result[X]) >= EPSILON)
        {
            throw POV_EXCEPTION_STRING("DNoise X error");
        }
        if (fabs(portable_res[Y] - result[Y]) >= EPSILON)
        {
            throw POV_EXCEPTION_STRING("DNoise Y error");
        }
        if (fabs(portable_res[Z] - result[Z]) >= EPSILON)
        {
            throw POV_EXCEPTION_STRING("DNoise Z error");
        }

    }

#endif



    _mm256_zeroupper();
    return;

}
Esempio n. 26
0
void Warp_EPoint (VECTOR TPoint, const VECTOR EPoint, const TPATTERN *TPat)
{
	VECTOR PTurbulence,RP;
	int Axis,i;
	int blockX = 0, blockY = 0, blockZ = 0 ;
	SNGL BlkNum;
	DBL  Length;
	DBL  Strength;
	WARP *Warp=TPat->Warps;
	TURB *Turb;
	TRANS *Tr;
	REPEAT *Repeat;
	BLACK_HOLE *Black_Hole;
	VECTOR Delta, Center;

	Assign_Vector(TPoint, EPoint);

	while (Warp != NULL)
	{
		switch(Warp->Warp_Type)
		{
			case CLASSIC_TURB_WARP:
				if ((TPat->Type == MARBLE_PATTERN) ||
				    (TPat->Type == NO_PATTERN)     ||
				    (TPat->Type == WOOD_PATTERN))
				{
					break;
				}
			/* If not a special type, fall through to next case */

			case EXTRA_TURB_WARP:
				Turb=(TURB *)Warp;
				DTurbulence (PTurbulence, TPoint, Turb);
				TPoint[X] += PTurbulence[X] * Turb->Turbulence[X];
				TPoint[Y] += PTurbulence[Y] * Turb->Turbulence[Y];
				TPoint[Z] += PTurbulence[Z] * Turb->Turbulence[Z];
				break;

			case NO_WARP:
				break;

			case TRANSFORM_WARP:
				Tr=(TRANS *)Warp;
				MInvTransPoint(TPoint, TPoint, &(Tr->Trans));
				break;

			case REPEAT_WARP:
				Repeat=(REPEAT *)Warp;
				Assign_Vector(RP,TPoint);
				Axis=Repeat->Axis;
				BlkNum=(SNGL)floor(TPoint[Axis]/Repeat->Width);

				RP[Axis]=TPoint[Axis]-BlkNum*Repeat->Width;

				if (((int)BlkNum) & 1)
				{
					VEvaluateEq(RP,Repeat->Flip);
					if ( Repeat->Flip[Axis] < 0 )
					{
						RP[Axis] = Repeat->Width+RP[Axis];
					}
				}

				VAddScaledEq(RP,BlkNum,Repeat->Offset);
				Assign_Vector(TPoint,RP);
				break;

			case BLACK_HOLE_WARP:
				Black_Hole = (BLACK_HOLE *) Warp ;
				Assign_Vector (Center, Black_Hole->Center) ;

				if (Black_Hole->Repeat)
				{
					/* first, get the block number we're in for each dimension  */
					/* block numbers are (currently) calculated relative to 0   */
					/* we use floor () since it correctly returns -1 for the
					   first block below 0 in each axis                         */
					/* one final point - we could run into overflow problems if
					   the repeat vector was small and the scene very large.    */
					if (Black_Hole->Repeat_Vector [X] >= EPSILON)
						blockX = (int) floor (TPoint [X] / Black_Hole->Repeat_Vector [X]) ;

					if (Black_Hole->Repeat_Vector [Y] >= EPSILON)
						blockY = (int) floor (TPoint [Y] / Black_Hole->Repeat_Vector [Y]) ;

					if (Black_Hole->Repeat_Vector [Z] >= EPSILON)
						blockZ = (int) floor (TPoint [Z] / Black_Hole->Repeat_Vector [Z]) ;

					if (Black_Hole->Uncertain)
					{
						/* if the position is uncertain calculate the new one first */
						/* this will allow the same numbers to be returned by frand */

						int seed = Hash3d (blockX, blockY, blockZ);
						Center [X] += WarpRands(seed) * Black_Hole->Uncertainty_Vector [X] ;
						Center [Y] += WarpRands(seed + 1) * Black_Hole->Uncertainty_Vector [Y] ;
						Center [Z] += WarpRands(seed + 2) * Black_Hole->Uncertainty_Vector [Z] ;
					}

					Center [X] += Black_Hole->Repeat_Vector [X] * blockX ;
					Center [Y] += Black_Hole->Repeat_Vector [Y] * blockY ;
					Center [Z] += Black_Hole->Repeat_Vector [Z] * blockZ ;
				}

				VSub (Delta, TPoint, Center) ;
				VLength (Length, Delta) ;

				/* Length is the distance from the centre of the black hole */
				if (Length >= Black_Hole->Radius) break ;

				if (Black_Hole->Type == 0)
				{
					/* now convert the length to a proportion (0 to 1) that the point
					   is from the edge of the black hole. a point on the perimeter
					   of the black hole will be 0.0 ; a point at the centre will be
					   1.0 ; a point exactly halfway will be 0.5, and so forth. */
					Length = (Black_Hole->Radius - Length) / Black_Hole->Radius ;

					/* Strength is the magnitude of the transformation effect. firstly,
					   apply the Power variable to Length. this is meant to provide a
					   means of controlling how fast the power of the Black Hole falls
					   off from its centre. if Power is 2.0, then the effect is inverse
					   square. increasing power will cause the Black Hole to be a lot
					   weaker in its effect towards its perimeter. 
					     
					   finally we multiply Strength with the Black Hole's Strength
					   variable. if the resultant value exceeds 1.0 we clip it to 1.0.
					   this means a point will never be transformed by more than its
					   original distance from the centre. the result of this clipping
					   is that you will have an 'exclusion' area near the centre of
					   the black hole where all points whose final value exceeded or
					   equalled 1.0 were moved by a fixed amount. this only happens
					   if the Strength value of the Black Hole was greater than one. */

					Strength = pow (Length, Black_Hole->Power) * Black_Hole->Strength ;
					if (Strength > 1.0) Strength = 1.0 ;

					/* if the Black Hole is inverted, it gives the impression of 'push-
					   ing' the pattern away from its centre. otherwise it sucks. */
					VScaleEq (Delta, Black_Hole->Inverted ? -Strength : Strength) ;

					/* add the scaled Delta to the input point to end up with TPoint. */
					VAddEq (TPoint, Delta) ;
				}
				break;

			/* 10/23/1998 Talious added SPherical Cylindrical and toroidal
			warps */

			case CYLINDRICAL_WARP:
				warp_cylindrical(TPoint, (CYLW *)Warp);
				break;

			case PLANAR_WARP:
				warp_planar(TPoint, (PLANARW *)Warp);
				break;

			case SPHERICAL_WARP:
				warp_spherical(TPoint, (SPHEREW *)Warp);
				break;

			case TOROIDAL_WARP:
				warp_toroidal(TPoint, (TOROIDAL *) Warp);
				break;

			case CUBIC_WARP:
				warp_cubic(TPoint);
				break;

			default:
				throw POV_EXCEPTION_STRING("Warp type not yet implemented.");
		}
		Warp=Warp->Next_Warp;
	}

	for (i=X; i<=Z; i++)
		if (TPoint[i] > COORDINATE_LIMIT)
			TPoint[i]= COORDINATE_LIMIT;
		else
			if (TPoint[i] < -COORDINATE_LIMIT)
				TPoint[i] = -COORDINATE_LIMIT;

}
Esempio n. 27
0
WARP *Create_Warp (int Warp_Type)
{
	WARP *New;
	TURB *TNew;
	REPEAT *RNew;
	TRANS *TRNew;
	BLACK_HOLE *BNew;
	TOROIDAL *TorNew;
	SPHEREW *SNew;
	CYLW *CNew;
	PLANARW *PNew;

	New = NULL;

	switch (Warp_Type)
	{
		case CLASSIC_TURB_WARP:
		case EXTRA_TURB_WARP:

			TNew = (TURB *)POV_MALLOC(sizeof(TURB),"turbulence struct");

			Make_Vector(TNew->Turbulence,0.0,0.0,0.0);

			TNew->Octaves = 6;
			TNew->Omega = 0.5;
			TNew->Lambda = 2.0;

			New = (WARP *)TNew;

			break;

		case REPEAT_WARP:

			RNew = (REPEAT *)POV_MALLOC(sizeof(REPEAT),"repeat warp");

			RNew->Axis = -1;
			RNew->Width = 0.0;

			Make_Vector(RNew->Offset,0.0,0.0,0.0);
			Make_Vector(RNew->Flip,1.0,1.0,1.0);

			New = (WARP *)RNew;

			break;

		case BLACK_HOLE_WARP:
			BNew = (BLACK_HOLE *)POV_MALLOC (sizeof (BLACK_HOLE), "black hole warp") ;
			Make_Vector (BNew->Center, 0.0, 0.0, 0.0) ;
			Make_Vector (BNew->Repeat_Vector, 0.0, 0.0, 0.0) ;
			Make_Vector (BNew->Uncertainty_Vector, 0.0, 0.0, 0.0) ;
			BNew->Strength = 1.0 ;
			BNew->Power = 2.0 ;
			BNew->Radius = 1.0 ;
			BNew->Radius_Squared = 1.0 ;
			BNew->Inverse_Radius = 1.0 ;
			BNew->Inverted = false ;
			BNew->Type = 0 ;
			BNew->Repeat = false ;
			BNew->Uncertain = false ;
			New = (WARP *) BNew ;
			break ;

		case TRANSFORM_WARP:

			TRNew = (TRANS *)POV_MALLOC(sizeof(TRANS),"pattern transform");

			MIdentity (TRNew->Trans.matrix);
			MIdentity (TRNew->Trans.inverse);

			New = (WARP *)TRNew;

			break;

		case SPHERICAL_WARP:
			SNew = (SPHEREW *)POV_MALLOC(sizeof(SPHEREW),"cylindrical warp");
			Make_Vector (SNew->Orientation_Vector, 0.0, 0.0, 1.0) ;
			SNew->DistExp = 0.0;
			New = (WARP *)SNew;
			break;

		case PLANAR_WARP:
			PNew = (PLANARW *)POV_MALLOC(sizeof(PLANARW),"planar warp");
			Make_Vector (PNew->Orientation_Vector, 0.0, 0.0, 1.0) ;
			PNew->OffSet = 0.0;
			New = (WARP *)PNew;
			break;

		case CYLINDRICAL_WARP:
			CNew = (CYLW *)POV_MALLOC(sizeof(CYLW),"cylindrical warp");
			Make_Vector (CNew->Orientation_Vector, 0.0, 0.0, 1.0) ;
			CNew->DistExp = 0.0;
			New = (WARP *)CNew;
			break;

		case TOROIDAL_WARP:
			TorNew = (TOROIDAL *)POV_MALLOC(sizeof(TOROIDAL),"toroidal warp");
			TorNew->MajorRadius = 1.0 ;
			TorNew->DistExp = 0.0;
			Make_Vector (TorNew->Orientation_Vector, 0.0, 0.0, 1.0) ;
			New = (WARP *) TorNew;
			break;

		// JN2007: Cubic warp
		case CUBIC_WARP:
			New = (WARP *)POV_MALLOC(sizeof(WARP),"cubic warp");
			break;

		default:
			throw POV_EXCEPTION_STRING("Unknown Warp type.");
	}

	New->Warp_Type = Warp_Type;
	New->Prev_Warp = NULL;
	New->Next_Warp = NULL;

	return(New);
}
Esempio n. 28
0
int BicubicPatch::bezier_tree_walker(const BasicRay &ray, const BEZIER_NODE *Node, IStack& Depth_Stack, TraceThreadData *Thread)
{
    int i, cnt = 0;
    DBL Depth, u, v;
    DBL uu[3], vv[3];
    Vector3d N, P;
    TripleVector3d V1;
    Vector2d UV;
    Vector2d uv_point, tpoint;
    const BEZIER_CHILDREN *Children;
    const BEZIER_VERTICES *Vertices;

    /*
     * Make sure the ray passes through a sphere bounding
     * the control points of the patch.
     */

    if (!spherical_bounds_check(ray, Node->Center, Node->Radius_Squared))
    {
        return (0);
    }

    /*
     * If this is an interior node then continue the descent,
     * else do a check against the vertices.
     */

    if (Node->Node_Type == BEZIER_INTERIOR_NODE)
    {
        Children = reinterpret_cast<const BEZIER_CHILDREN *>(Node->Data_Ptr);

        for (i = 0; i < Node->Count; i++)
        {
            cnt += bezier_tree_walker(ray, Children->Children[i], Depth_Stack, Thread);
        }
    }
    else if (Node->Node_Type == BEZIER_LEAF_NODE)
    {
        Vertices = reinterpret_cast<const BEZIER_VERTICES *>(Node->Data_Ptr);

        V1[0] = Vertices->Vertices[0];
        V1[1] = Vertices->Vertices[1];
        V1[2] = Vertices->Vertices[2];

        uu[0] = Vertices->uvbnds[0];
        uu[1] = Vertices->uvbnds[0];
        uu[2] = Vertices->uvbnds[1];
        vv[0] = Vertices->uvbnds[2];
        vv[1] = Vertices->uvbnds[3];
        vv[2] = Vertices->uvbnds[3];

        /*
         * Triangulate this subpatch, then check for
         * intersections in the triangles.
         */

        if (intersect_subpatch(ray, V1, uu, vv, &Depth, P, N, &u, &v))
        {
            if (Clip.empty() || Point_In_Clip(P, Clip, Thread))
            {
                /* transform current point from uv space to texture space */
                uv_point[0] = v;
                uv_point[1] = u;
                Compute_Texture_UV(uv_point, ST, tpoint);

                UV[U] = tpoint[0];
                UV[V] = tpoint[1];
                Depth_Stack->push(Intersection(Depth, P, N, UV, this));

                cnt++;
            }
        }

        V1[1] = V1[2];
        V1[2] = Vertices->Vertices[3];

        uu[1] = uu[2]; uu[2] = Vertices->uvbnds[1];
        vv[1] = vv[2]; vv[2] = Vertices->uvbnds[2];

        if (intersect_subpatch(ray, V1, uu, vv, &Depth, P, N, &u, &v))
        {
            if (Clip.empty() || Point_In_Clip(P, Clip, Thread))
            {
                /* transform current point from object space to texture space */
                uv_point[0] = v;
                uv_point[1] = u;
                Compute_Texture_UV(uv_point, ST, tpoint);

                UV[U] = tpoint[0];
                UV[V] = tpoint[1];
                Depth_Stack->push(Intersection(Depth, P, N, UV, this));

                cnt++;
            }
        }
    }
    else
    {
        throw POV_EXCEPTION_STRING("Bad Node type in bezier_tree_walker().");
    }

    return (cnt);
}
Esempio n. 29
0
void Perturb_Normal(Vector3d& Layer_Normal, const TNORMAL *Tnormal, const Vector3d& EPoint, Intersection *Intersection, const Ray *ray, TraceThreadData *Thread)
{
    Vector3d TPoint,P1;
    DBL value1,Amount;
    int i;
    shared_ptr<NormalBlendMap> Blend_Map;

    if (Tnormal==NULL)
    {
        return;
    }

    /* If normal_map present, use it and return */

    Blend_Map = std::tr1::dynamic_pointer_cast<NormalBlendMap>(Tnormal->Blend_Map);
    if (Blend_Map != NULL)
    {
        if (Tnormal->Type == UV_MAP_PATTERN)
        {
            Vector2d UV_Coords;

            /* Don't bother warping, simply get the UV vect of the intersection */
            Intersection->Object->UVCoord(UV_Coords, Intersection, Thread);
            TPoint[X] = UV_Coords[U];
            TPoint[Y] = UV_Coords[V];
            TPoint[Z] = 0;

            Perturb_Normal(Layer_Normal,Blend_Map->Blend_Map_Entries[0].Vals,TPoint,Intersection,ray,Thread);
            Layer_Normal.normalize();
            Intersection->PNormal = Layer_Normal; /* -hdf- June 98 */

            return;
        }
        else if (Tnormal->Type != AVERAGE_PATTERN)
        {
            const NormalBlendMapEntry *Prev, *Cur;
            DBL prevWeight, curWeight;

            /* NK 19 Nov 1999 added Warp_EPoint */
            Warp_EPoint (TPoint, EPoint, Tnormal);
            value1 = Evaluate_TPat(Tnormal, TPoint, Intersection, ray, Thread);

            Blend_Map->Search (value1,Prev,Cur,prevWeight,curWeight);

            Warp_Normal(Layer_Normal,Layer_Normal, Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
            P1 = Layer_Normal;

            Warp_EPoint (TPoint, EPoint, Tnormal);

            Perturb_Normal(Layer_Normal,Cur->Vals,TPoint,Intersection,ray,Thread);

            if (Prev != Cur)
            {
                Perturb_Normal(P1,Prev->Vals,TPoint,Intersection,ray,Thread);

                Layer_Normal = prevWeight * P1 + curWeight * Layer_Normal;
            }

            UnWarp_Normal(Layer_Normal,Layer_Normal, Tnormal, Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

            Layer_Normal.normalize();

            Intersection->PNormal = Layer_Normal; /* -hdf- June 98 */

            return;
        }
        // TODO - what if Tnormal->Type == AVERAGE_PATTERN?
    }

    /* No normal_map. */

    if (Tnormal->Type <= LAST_NORM_ONLY_PATTERN)
    {
        Warp_Normal(Layer_Normal,Layer_Normal, Tnormal,
                    Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

        Warp_EPoint (TPoint, EPoint, Tnormal);

        switch (Tnormal->Type)
        {
        case BITMAP_PATTERN:
            bump_map    (TPoint, Tnormal, Layer_Normal);
            break;
        case BUMPS_PATTERN:
            bumps       (TPoint, Tnormal, Layer_Normal);
            break;
        case DENTS_PATTERN:
            dents       (TPoint, Tnormal, Layer_Normal, Thread);
            break;
        case RIPPLES_PATTERN:
            ripples     (TPoint, Tnormal, Layer_Normal, Thread);
            break;
        case WAVES_PATTERN:
            waves       (TPoint, Tnormal, Layer_Normal, Thread);
            break;
        case WRINKLES_PATTERN:
            wrinkles    (TPoint, Tnormal, Layer_Normal);
            break;
        case QUILTED_PATTERN:
            quilted     (TPoint, Tnormal, Layer_Normal);
            break;
        case FACETS_PATTERN:
            facets      (TPoint, Tnormal, Layer_Normal, Thread);
            break;
        case AVERAGE_PATTERN:
            Do_Average_Normals (TPoint, Tnormal, Layer_Normal, Intersection, ray, Thread);
            break;
        default:
            throw POV_EXCEPTION_STRING("Normal pattern not yet implemented.");
        }

        UnWarp_Normal(Layer_Normal,Layer_Normal, Tnormal,
                      Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));
    }
    else
    {
        shared_ptr<SlopeBlendMap> slopeMap = std::tr1::dynamic_pointer_cast<SlopeBlendMap>(Tnormal->Blend_Map);

        Warp_Normal(Layer_Normal,Layer_Normal, Tnormal,
                    Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

        // TODO FIXME - two magic fudge factors
        Amount=Tnormal->Amount * -5.0; /*fudge factor*/
        Amount*=0.02/Tnormal->Delta; /* NK delta */

        /* warp the center point first - this is the last warp */
        Warp_EPoint(TPoint,EPoint,Tnormal);

        for(i=0; i<=3; i++)
        {
            P1 = TPoint + (DBL)Tnormal->Delta * Pyramid_Vect[i]; /* NK delta */
            value1 = Do_Slope_Map(Evaluate_TPat(Tnormal, P1, Intersection, ray, Thread), slopeMap.get());
            Layer_Normal += (value1*Amount) * Pyramid_Vect[i];
        }

        UnWarp_Normal(Layer_Normal,Layer_Normal,Tnormal,
                      Test_Flag(Tnormal,DONT_SCALE_BUMPS_FLAG));

    }

    if ( Intersection )
        Intersection->PNormal = Layer_Normal; /* -hdf- June 98 */
}
Esempio n. 30
0
void Cone::Compute_Cone_Data()
{
    DBL tlen, len, tmpf;
    Vector3d tmpv, axis, origin;

    /* Process the primitive specific information */

    /* Find the axis and axis length */

    axis = apex - base;

    len = axis.length();

    if (len < EPSILON)
    {
        throw POV_EXCEPTION_STRING("Degenerate cone/cylinder."); // TODO FIXME - should a possible error
    }
    else
    {
        axis /= len;
    }
    /* we need to trap that case first */
    if (fabs(apex_radius - base_radius) < EPSILON)
    {
        /* What we are dealing with here is really a cylinder */

        Set_Flag(this, CYLINDER_FLAG);

        Compute_Cylinder_Data();

        return;
    }

    if (apex_radius < base_radius)
    {
        /* Want the bigger end at the top */

        tmpv = base;
        base = apex;
        apex = tmpv;

        tmpf = base_radius;
        base_radius = apex_radius;
        apex_radius = tmpf;
        axis.invert();
    }
    /* apex & base are different, yet, it might looks like a cylinder */
    tmpf = base_radius * len / (apex_radius - base_radius);

    origin = base - axis * tmpf;

    tlen = tmpf + len;
    /* apex is always bigger here */
    if (((apex_radius - base_radius)*len/tlen) < EPSILON)
    {
        /* What we are dealing with here is really a cylinder */

        Set_Flag(this, CYLINDER_FLAG);

        Compute_Cylinder_Data();

        return;
    }

    dist = tmpf / tlen;
    /* Determine alignment */
    Compute_Coordinate_Transform(Trans, origin, axis, apex_radius, tlen);

    /* Recalculate the bounds */

    Compute_BBox();
}