`
One of the most interesting features in POV-Ray 3.5
are functions. They are powered by virtual machine. They are really fast but complex calculations are still
a little faster when compiled directly into executable file. My idea was to show how one can add own internal
(precompiled) function to the list of internal functions already builded in POV 3.5. As an example I choosed
f_triangle function. This function will return distance to specified triangle. First I have designed this function
in POV-Ray SDL. You can find it in iso_CSG
library as IC_Triangle macro. Then I have started rewrite it as internal function.
`

f_triangle function as pattern |
f_triangle isosurface displaced with bozo |
---|---|

`
Here are steps necessary to introduce own internal function. First you have to add your
function to the list of definition in Global functions block in fnintern.cpp file.
`

```
/*****************************************************************************
* Global functions
******************************************************************************/
DBL f_algbr_cyl1(DBL *ptr, unsigned int fn); // 0
:
:
DBL f_noise_generator(DBL *ptr, unsigned int fn); // 78
DBL f_triangle(DBL *ptr, unsigned int fn); // 79
```

`
Now we have to add this function to the list POVFPU_TrapTable. The that second part of this addition
10 + 3 means that ther would be 13 parameters to this function: 3 for x,y,z and 10 for additional
parameters - in this case coordinates of triangle vertices and last for triangle thickness. Additionally
POVFPU_TrapTableSize have to be increased to point last (NULL) entry in list of internal functions.
`

/***************************************************************************** * Global variables ******************************************************************************/ Trap POVFPU_TrapTable[] = { { f_algbr_cyl1, 5 + 3 }, // 0 : : { f_triangle, 10 + 3 }, // 79 { NULL, 0 } }; TrapS POVFPU_TrapSTable[] = { { f_pigment, 0 + 3 }, // 0 { f_transform, 0 + 3 }, // 1 { f_spline, 0 + 1 }, // 2 { NULL, 0 } }; unsigned int POVFPU_TrapTableSize = 80; unsigned int POVFPU_TrapSTableSize = 3;

`
Final step is just to write content for f_triangle function. To make this code shorter I have defined 3 additional
definitions. Place it in any place where they will be visible for compiler, for example in vectors.h
`

```
// macro to prevent zero-lenth normalizing
#define VNormalizeEqNotZeroLength(a,len) \
{ \
len=sqrt((a)[X]*(a)[X]+(a)[Y]*(a)[Y]+(a)[Z]*(a)[Z]); \
if(len<=0) \
Error( "Can't normalize zero length vector" ); \
(a)[X]/=len; \
(a)[Y]/=len; \
(a)[Z]/=len; \
}
// macro to prevent zero-lenth normalized cross product
#define VNormalizeCrossNotZeroLength(a,v1,v2) \
{ \
DBL d_temp; \
\
VCross(a,v1,v2); \
VNormalizeEqNotZeroLength(a,d_temp); \
}
// macro to calculate appearance for one edge
#define DistanceToEdge( Dist , Edge , End , Point ) \
{ \
DBL Edge_To_Point; \
DBL Edge_Length,Rd; \
\
VNormalizeEqNotZeroLength(Edge,Edge_Length); \
VDot(Rd,Edge,End); \
VDot(Edge_To_Point,Edge,Point); \
Edge_To_Point=max(min(Edge_To_Point-Rd,Edge_Length),0.0); \
VSub(v_temp,Point,End); \
VSubScaledEq(v_temp,Edge_To_Point,Edge); \
VLength(Dist,v_temp); \
}
```

`
So we have now everything to code f_triangle in fnintern.cpp file. All parameters passed to this function
are available via macros PARAM... in DBL *ptr parameter. We have to only calculate and return result.
`

```
DBL f_triangle(DBL *ptr, unsigned int) // 79
{
// PARAM_X .. PARAM_Z - x,y,z function parameters
// PARAM(0) .. PARAM(2) - first vertex coordinates
// PARAM(3) .. PARAM(5) - second vertex coordinates
// PARAM(6) .. PARAM(8) - third vertex coordinates
// PARAM(9) - thickness
VECTOR v_temp,N,R1,R2,R3,E;
DBL Nd,Ed,El;
DBL Distance = 0.0;
VECTOR P0 = { PARAM_X, PARAM_Y, PARAM_Z };
VECTOR P1 = { PARAM(0), PARAM(1), PARAM(2) };
VECTOR P2 = { PARAM(3), PARAM(4), PARAM(5) };
VECTOR P3 = { PARAM(6), PARAM(7), PARAM(8) };
VSub(R1,P2,P1);
VSub(R2,P3,P2);
VSub(R3,P1,P3);
VNormalizeCrossNotZeroLength(N,R2,R3);
VNormalizeCrossNotZeroLength(E,N,R1);
VDot(Ed,E,P1);
VDot(El,E,P0);
if ( Ed < El )
{
VNormalizeCrossNotZeroLength(E,N,R2);
VDot(Ed,E,P2);
VDot(El,E,P0);
if ( Ed < El )
{
VNormalizeCrossNotZeroLength(E,N,R3);
VDot(Ed,E,P3);
VDot(El,E,P0);
if ( Ed < El )
{
VDot(Nd,N,P1);
VDot(Distance,N,P0);
Distance = fabs( Distance-Nd );
}
else
{
DistanceToEdge( Distance , R3 , P3 , P0 );
}
}
else
{
DistanceToEdge( Distance , R2 , P2 , P0 );
}
}
else
{
DistanceToEdge( Distance , R1 , P1 , P0 );
}
return ( Distance - (PARAM(9)/2) ) ;
}
```

`
After compilation you can use this function in your POV scripts this way:
`

#declare f_triangle=function{internal(79)}; #declare P1=-x; #declare P2=y; #declare P3=x-y; #macro List(P) #local Px=P.x; #local Py=P.y; #local Pz=P.z; Px,Py,Pz #end #declare Pattern = function{f_triangle(x,y,z,List(P1),List(P2),List(P3),.1)};

`
Do you want to know how to use other internals in your own function?
Do you want to know how to use patterns there to speedup isosurface calculations ? Ask me
for next tutorial. I want to know that somebody needs it :-).
`