This is my frustrum culling library which I use in my shadow system:
; -----------------------------------------------------------------------------------------------------------------------------------
; PolyClip - Swift Polygon Clipping System - Copyright 2004 Shawn Swift
; -----------------------------------------------------------------------------------------------------------------------------------
;
; Find out more about my shadow, and other systems, here:
;
; Shadows, Terrains, GUI/HUD/2D Overlays in 3D:
; <a href="http://www.blitzbasic.com/logs/userlog.php?user=963&log=147" target="_blank">http://www.blitzbasic.com/logs/userlog.php?user=963&log=147</a>
;
; 2D sprite system for all versions of Blitz with five blending modes including alpha, add, and multiply:
; <a href="http://www.blitzbasic.com/toolbox/toolbox.php?tool=58" target="_blank">http://www.blitzbasic.com/toolbox/toolbox.php?tool=58</a>
;
; I accept payment via Paypal, Western Union, personal checks made out in US dolalrs, and bank transfers.
; Paypal is the preffered method. If you wish to pay via paypal, send payment to scswift@...
;
; -----------------------------------------------------------------------------------------------------------------------------------
;
; This system supports polygons with any number of sides, but it defaults to a max of 4 sides per input poly. The output polygons
; may have up to 10 sides. Change the constant CLIP_MAX_POLY_SIDES to increase the number of sides you can use on input polygons.
; And keep in mind that if you clip a polygon and then re-input it into the system for additional clipping, you'll have to make
; sure that CLIP_MAX_POLY_SIDES is large enough to support the potentially much larger resulting polygon.
;
; The system also defaults to allowing only six clipping planes, which may not be enough if you want to clip polygons against shapes
; other than cubes. Again, increasing CLIP_MAX_POLY_SIDES will increase this value. See CLIP_MAX_POLY_SIDES for more details.
;
;
; What can you do with this system?
;
; 1. Cut a polygon with a plane, returning only the half on the inside side of the plane. (Side facimg away from plane's normal)
; 2. Clip a polygon to the viewport by specifying a iew frustrum with 4, 5 or 6 planes.
; 3. Quickly determine if an individual triangle is in a frustrum or other polyhedra formed by planes, without having to set up
; a polygon or delete the returned data.
;
; Instructions:
;
; If you want to clip a polygon, create some planes like so:
;
; TopPlane.CLIP_Plane = CLIP_CreatePlane(A#, B#, C#, D#)
;
; Then create a polygon like this:
;
; ThisPoly.CLIP_Poly = CLIP_CreateTri(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#)
;
; Or, create one manually with the CLIP_CreatePoly() and CLIP_AddVertex() commands.
; You can also adjust the values for a vertex. If a polygon has 4 vertcies, you can index them with the values 0..3.
; AddVertex also returns the index number of the most recently created vertex if you would like to use that.
;
; Why set the normal, color, alpha, or texture coordinates of a vertex?
;
; When the system clips a polygon, it creates a new polygon, sometimes with additional vertices. By specifying these values,
; you can have all of them automaitcally interpolated and computed for all the vertices in the new polyon!
;
; And finally, call ClipPoly to clip an individual polygon, or ClipPolys to clip all polygons at once.
;
; You can also skip the polygon creation steps and test tris against a region bounded by planes with CLIP_TriInFrustum().
;
; -----------------------------------------------------------------------------------------------------------------------------------
;
; This system uses the Sutherland-Hodgeman polygon clipping algorithm.
;
; Here is some pseudocode that describes the algorithm:
;
;
; CURRENT_POLYGON = Polygon to be clipped.
;
; For each plane in the frustum:
;
; For each pair of vertices (v1,v2) forming an edge of CURRENT_POLYGON:
;
; (Inside means a vertex is on the side of the current plane that faces away from the plane's normal.)
;
; If v1 inside, v2 inside = output v2
; If v1 inside, v2 outside = output intersection
; If v1 outside, v2 outside = no output
; If v1 outside, v2 inside = output v2 and intersection
;
; Next
;
; CURRENT_POLYGON = Polygon formed by vertcies output from for loop.
; If no vertcies in CURRENT_POLYGON exit loop.
;
; Next
;
; Resulting polygon is clipped to frustum.
;
; Returned points will have same winding as input points. In other words, if input polygon is wound counterclockwise,
; resulting polygon will also have its vertices wound counterclockwise.
;
; If no vertices in resulting polygon, polygon was completely outside frustum.
;
; -----------------------------------------------------------------------------------------------------------------------------------
;
; Rather than use this system to do all your clipping as-is, you should use it in conjunction with a hash-table using
; "clipping flags" for each vertex, and use that to determine if you should send the triangle to this system. You can do the
; vertex text with the CLIP_Point_Inside_Plane() function after you have set up your planes.
;
; Read this article for more info:
; <a href="http://www.gamasutra.com/features/19990507/polygon_clipping_01.htm" target="_blank">http://www.gamasutra.com/features/19990507/polygon_clipping_01.htm</a>
;
; -----------------------------------------------------------------------------------------------------------------------------------
; CLIP_MAX_POLY_SIDES is the maximum number of sides a polygon can have.
; It must ALWAYS be larger than the total number of sides on the polygons you input into the system!
;
; You can calculate this number like so: (Max sides on input polygon) + (Max number of clipping planes)
;
; The default value of 10 assumes that the input polygon will have 3 or 4 sides, (tri or quad) and that there will be
; a maximum of 6 clipping planes.
Const CLIP_MAX_POLY_SIDES = 10
Type CLIP_Plane
Field A#
Field B#
Field C#
Field D#
End Type
; 564 bytes
Type CLIP_Poly
Field Vertices
Field Vx#[CLIP_MAX_POLY_SIDES]
Field Vy#[CLIP_MAX_POLY_SIDES]
Field Vz#[CLIP_MAX_POLY_SIDES]
Field Vnx#[CLIP_MAX_POLY_SIDES]
Field Vny#[CLIP_MAX_POLY_SIDES]
Field Vnz#[CLIP_MAX_POLY_SIDES]
Field Vu0#[CLIP_MAX_POLY_SIDES]
Field Vv0#[CLIP_MAX_POLY_SIDES]
Field Vu1#[CLIP_MAX_POLY_SIDES]
Field Vv1#[CLIP_MAX_POLY_SIDES]
Field Vr#[CLIP_MAX_POLY_SIDES]
Field Vg#[CLIP_MAX_POLY_SIDES]
Field Vb#[CLIP_MAX_POLY_SIDES]
Field Va#[CLIP_MAX_POLY_SIDES]
End Type
; These variables will contain the output from CLIP_Line_Intersect_Plane()
Global CLIP_Intersect_X#
Global CLIP_Intersect_Y#
Global CLIP_Intersect_Z#
Global CLIP_Intersect_U#
; These variables will contain the output from CLIP_InterpolateNormal()
Global CLIP_Normal_X#
Global CLIP_Normal_Y#
Global CLIP_Normal_Z#
; These variables will contain the output from CLIP_CalculateTriPlane() and CLIP_Calculate2DLine().
Global CLIP_A#
Global CLIP_B#
Global CLIP_C#
Global CLIP_D#
; These variables will contain the output from CLIP_CalculateTriNormal()
Global POLY_Temp.CLIP_Poly = New CLIP_Poly
; -----------------------------------------------------------------------------------------------------------------------------------
; This function creates a new clipping plane with the specified plane equation.
;
; Returns a pointer to the plane, but you don't need to save it because there is no function in the system you need to pass
; that pointer to. It is just there for future expansion.
;
; Use CLIP_FreePlanes() to free all the planes you've created when you're done with them and want to make new ones.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CreatePlane.CLIP_Plane(A#, B#, C#, D#)
Local NewPlane.CLIP_Plane
NewPlane = New CLIP_Plane
NewPlane\A# = A#
NewPlane\B# = B#
NewPlane\C# = C#
NewPlane\D# = D#
Return NewPlane
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function creates a new triangle and returns a pointer to it.
;
; It does not matter if polygons in this system are wound clockwise or counterclockwise.
; They are all clipped the same, and the resulting polygon will have the same winding as the original.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CreateTri.CLIP_Poly(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#)
Local NewPoly.CLIP_Poly
NewPoly = New CLIP_Poly
CLIP_AddVertex(NewPoly, X1#, Y1#, Z1#)
CLIP_AddVertex(NewPoly, X2#, Y2#, Z2#)
CLIP_AddVertex(NewPoly, X3#, Y3#, Z3#)
Return NewPoly
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function creates a new quad and returns a pointer to it.
;
; It does not matter if polygons in this system are wound clockwise or counterclockwise.
; They are all clipped the same, and the resulting polygon will have the same winding as the original.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CreateQuad.CLIP_Poly(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#, X4#, Y4#, Z4#)
Local NewPoly.CLIP_Poly
NewPoly = New CLIP_Poly
CLIP_AddVertex(NewPoly, X1#, Y1#, Z1#)
CLIP_AddVertex(NewPoly, X2#, Y2#, Z2#)
CLIP_AddVertex(NewPoly, X3#, Y3#, Z3#)
CLIP_AddVertex(NewPoly, X4#, Y4#, Z4#)
Return NewPoly
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function creates a new polygon and returns a pointer to it.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CreatePoly.CLIP_Poly()
Return New CLIP_Poly
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function adds a vertex to a polygon, and returns its index number.
;
; Vertices must be added in order, and if wound in a clockwise direction the face normal will point towards you.
;
; Vertex indices range from 0 to vertices-1.
;
; Poly is the polygon to add the vertex to.
; XYZ is the vertex position. (Optional)
; Vertex color defaults to 255,255,255.
; Vertex alpha defaults to 1.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_AddVertex(Poly.CLIP_poly, X#=0, Y#=0, Z#=0)
Local Index
Index = Poly\Vertices
Poly\Vertices = Poly\Vertices + 1
Poly\Vx#[Index] = X#
Poly\Vy#[Index] = Y#
Poly\Vz#[Index] = Z#
Poly\Vr#[Index] = 255
Poly\Vg#[Index] = 255
Poly\Vb#[Index] = 255
Poly\Va#[Index] = 1
Return Index
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function sets the position of a vertex.
;
; Poly is the poly which contains the vertex.
; Index is the vertex index returned from CLIP_AddVertex().
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SetVertexPosition(Poly.CLIP_Poly, Index, X#, Y#, Z#)
Poly\Vx#[Index] = X#
Poly\Vy#[Index] = Y#
Poly\Vz#[Index] = Z#
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function sets the normal of a vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SetVertexNormal(Poly.CLIP_Poly, Index, Nx#, Ny#, Nz#)
Poly\Vnx#[Index] = Nx#
Poly\Vny#[Index] = Ny#
Poly\Vnz#[Index] = Nz#
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function sets the texture coordinates of a vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SetVertexUV(Poly.CLIP_Poly, Index, U#, V#, Coord_Set=0)
If Coord_Set = 0
Poly\Vu0#[Index] = U#
Poly\Vv0#[Index] = V#
Else
Poly\Vu1#[Index] = U#
Poly\Vv1#[Index] = V#
EndIf
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function sets the color of a vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SetVertexColor(Poly.CLIP_Poly, Index, R#, G#, B#)
Poly\Vr#[Index] = R#
Poly\Vg#[Index] = G#
Poly\Vb#[Index] = B#
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function sets the alpha of a vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SetVertexAlpha(Poly.CLIP_Poly, Index, Alpha#)
Poly\Va#[Index] = Alpha#
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function gets the position of a vertex.
; Set XYZ to 0 if you want the X component, 1 for Y, and 2 for Z.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_GetVertexPosition#(Poly.CLIP_Poly, Index, XYZ)
Select XYZ
Case 0 Return Poly\Vx#[Index]
Case 1 Return Poly\Vy#[Index]
Case 2 Return Poly\Vz#[Index]
End Select
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function gets the normal of a vertex.
; Set XYZ to 0 if you want the X component, 1 for Y, and 2 for Z.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_GetVertexNormal#(Poly.CLIP_Poly, Index, XYZ)
Select XYZ
Case 0 Return Poly\Vnx#[Index]
Case 1 Return Poly\Vny#[Index]
Case 2 Return Poly\Vnz#[Index]
End Select
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function gets the texture coordinates of a vertex.
;
; Set UV to 0 to get the U component, and 1 to get the V.
; Set Coord_Set to 0 to get the first set of UV coordinates, and 1 to get the second. (Optional)
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_GetVertexUV#(Poly.CLIP_Poly, Index, UV, Coord_Set=0)
If Coord_Set = 0
If UV = 0 Then Return Poly\Vu0#[Index]
If UV = 1 Then Return Poly\Vv0#[Index]
Else
If UV = 0 Then Return Poly\Vu1#[Index]
If UV = 1 Then Return Poly\Vv1#[Index]
EndIf
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function gets the color of a vertex.
;
; Set RGB to 0 if you want the R component, 1 for G, and 2 for B.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_GetVertexColor#(Poly.CLIP_Poly, Index, RGB)
Select RGB
Case 0 Return Poly\Vr#[Index]
Case 1 Return Poly\Vg#[Index]
Case 2 Return Poly\Vb#[Index]
End Select
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function gets the alpha of a vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_GetVertexAlpha#(Poly.CLIP_Poly, Index)
Return Poly\Va#[Index]
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function deletes all planes that have been added to the system.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_FreePlanes()
Local LOOP_Plane.CLIP_Plane
For LOOP_Plane = Each CLIP_Plane
Delete LOOP_Plane
Next
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function deletes all polygons that have been added to the system.
; CLIP_TriInFrustum does NOT leave any polygons lying around that you need to delete later.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_FreePolys()
Local LOOP_Poly.CLIP_Poly
For LOOP_Poly = Each CLIP_Poly
Delete LOOP_Poly
Next
; Recreate the polygon that we use for scratch.
POLY_Temp = New CLIP_Poly
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function frees Kevin Mitnick and returns a pointer to a high profile computer security job.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_FreeKevinMitnick()
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns TRUE if the specified triangle is intersecting/inside the region bounded by the clipping planes.
; CLIP_TriInFrustum does NOT leave any polygons lying around that you need to delete later.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_TriInFrustum(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#)
Local POLY_Input.CLIP_Poly
; Do a quick but inaccurate test first.
; If this test is positive, triangle MAY be inside frustum.
If CLIP_FastTriInFrustum(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#)
; Quick test says triangle MAY be inside frustum.
; Do slower, accurate test.
; Create the triangle.
POLY_Input = New CLIP_Poly
POLY_Input\Vertices = 3
POLY_Input\Vx#[0] = X1#
POLY_Input\Vy#[0] = Y1#
POLY_Input\Vz#[0] = Z1#
POLY_Input\Vx#[1] = X2#
POLY_Input\Vy#[1] = Y2#
POLY_Input\Vz#[1] = Z2#
POLY_Input\Vx#[2] = X3#
POLY_Input\Vy#[2] = Y3#
POLY_Input\Vz#[2] = Z3#
; Clip the triangle.
CLIP_ClipPoly(POLY_Input, False)
; Was the polygon in the frustum?
If POLY_Input\Vertices > 0
; Poly has vertices.
; Tri was inside or intersecting the frustum.
Delete POLY_Input
Return True
Else
; Poly has no vertices.
; Tri was completely outside the frustum.
Delete POLY_Input
Return False
EndIf
Else
; Quick test says triangle was DEFINITELY outside the frustum.
Return False
EndIf
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function is a fast test that returns TRUE if a triangle is MIGHT be in a frustum.
; Note that this test is INACCURATE, and will only tell you for sure that a triangle is NOT in the frustum.
; A more accurate test needs to be done after to say for sure that the triangle IS in the frustum.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_FastTriInFrustum(X1#, Y1#, Z1#, X2#, Y2#, Z2#, X3#, Y3#, Z3#)
Local LOOP_Plane.CLIP_Plane
Local A#, B#, C#, D#
For LOOP_Plane = Each CLIP_Plane
A# = LOOP_Plane\A#
B# = LOOP_Plane\B#
C# = LOOP_Plane\C#
D# = LOOP_Plane\D#
; Are all three vertcies of this triangle outside this plane?
If (X1#*A# + Y1#*B# + Z1#*C# + D#) > 0
If (X2#*A# + Y2#*B# + Z2#*C# + D#) > 0
If (X3#*A# + Y3#*B# + Z3#*C# + D#) > 0
; Yes.
; Triangle is DEFINITELY outside frustum!
Return False
EndIf
EndIf
EndIf
Next
; Triangle MAY be inside frustum, but we can't be sure.
Return True
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function is a fast test that returns TRUE if a triangle is MIGHT be in a frustum.
; Note that this test is INACCURATE, and will only tell you for sure that a triangle is NOT in the frustum.
; A more accurate test needs to be done after to say for sure that the triangle IS in the frustum.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_FastPolyInFrustum(Poly.CLIP_poly)
Local LOOP_Plane.CLIP_Plane
Local A#, B#, C#, D#
Local LOOP_Vertex
Local Outside
For LOOP_Plane = Each CLIP_Plane
Outside = True
; For each vertex in the polygon...
For LOOP_Vertex = 0 To Poly\Vertices-1
; Is this vertex inside this plane?
If (Poly\Vx#[LOOP_Vertex]*LOOP_Plane\A# + Poly\Vy#[LOOP_Vertex]*LOOP_Plane\B# + Poly\Vz#[LOOP_Vertex]*LOOP_Plane\C# + LOOP_Plane\D#) < 0
; Vertex is inside plane.
; Polygon cannot be outside this plane. Skip rest of vertices, and check poly against next plane.
Outside = False
Exit
Else
; Vertex is outside plane.
EndIf
Next
If Outside
; All vertcies were outside the last plane.
; Polygon is DEFINITELY outside frustum.
Return False
EndIf
Next
; Polygon was not outside any planes.
; Polygon MAY be inside frustum, but we can't be sure.
Return True
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns the distance of a point from a plane.
;
; If the point is in front of the plane, this distance will be positive.
; If the vertex is behind the plane, the distance will be negative.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Point_Distance_From_Plane(X#, Y#, Z#, A#, B#, C#, D#)
Return (X#*A# + Y#*B# + Z#*C# + D#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns true if a point is on the back side of a plane.
; A plane's front side is the direction in which its normal points.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Point_Inside_Plane(X#, Y#, Z#, A#, B#, C#, D#)
If (X#*A# + Y#*B# + Z#*C# + D#) < 0 Then Return True
Return False
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns TRUE if the specified sphere is intersecting/inside the region bounded by the clipping planes.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_PointInFrustum(X#, Y#, Z#)
Local LOOP_Plane.CLIP_Plane
; For each clipping plane...
For LOOP_Plane = Each CLIP_Plane
If Not ((X#*LOOP_Plane\A# + Y#*LOOP_Plane\B# + Z#*LOOP_Plane\C# + LOOP_Plane\D#) < 0) Then Return False
Next
Return True
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns true if a sphere is intersecting or behind the specified plane.
;
; XYZ = Sphere center
; Radius = Sphere radius
; ABCD = Plane equation
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Sphere_Inside_Plane(X#, Y#, Z#, Radius#, A#, B#, C#, D#)
If (X#*A# + Y#*B# + Z#*C# + D#) < Radius# Then Return True
Return False
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns TRUE if the specified sphere is intersecting/inside the region bounded by the clipping planes.
;
; This function is sloppy. While it finds all spheres inside/intersecting the region, it may also give false positives for
; some spheres outside the region but near it's corners.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_SphereInFrustum(X#, Y#, Z#, Radius#)
Local LOOP_Plane.CLIP_Plane
Local A#, B#, C#, D#
; For each clipping plane...
For LOOP_Plane = Each CLIP_Plane
; Store this clipping plane's equation.
A# = LOOP_Plane\A#
B# = LOOP_Plane\B#
C# = LOOP_Plane\C#
D# = LOOP_Plane\D#
If Not CLIP_Sphere_Inside_Plane(X#, Y#, Z#, Radius#, A#, B#, C#, D#) Then Return False
Next
Return True
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function takes a line segment and a plane as input, and outputs:
;
; 1. The global position at which the line intersects the plane, in CLIP_Intersect_XYZ#.
;
; 2. The line-relative position, in CLIP_Intersect_U#, where a value of 0..1 means the intersection point lies between V1 and V2,
; and a value less than 0 or greater than 1 means the intersection occured at a location outside the line segment.
;
; 3. TRUE if the line intersects the plane, and FALSE if the line runs near-parralel to the plane.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Line_Intersect_Plane(V1x#, V1y#, V1z#, V2x#, V2y#, V2z#, Pa#, Pb#, Pc#, Pd#)
Local Nx#, Ny#, Nz#
Local Dot#
; Calculate the normal of the line.
Nx# = V2x#-V1x#
Ny# = V2y#-V1y#
Nz# = V2z#-V1z#
; Calculate the dot product of the line's normal and the plane's normal.
Dot# = Pa#*Nx# + Pb#*Ny# + Pc#*Nz#
; If the line is nearly parralel to the plane, they do not intersect.
If (Abs(Dot#) < 0.0001) Then Return False
; Calculate the position on the line where the plane intersects it.
CLIP_Intersect_U# = -(Pd# + Pa#*V1x# + Pb#*V1y# + Pc#*V1z#) / Dot#
CLIP_Intersect_X# = V1x# + CLIP_Intersect_U#*Nx#
CLIP_Intersect_Y# = V1y# + CLIP_Intersect_U#*Ny#
CLIP_Intersect_Z# = V1z# + CLIP_Intersect_U#*Nz#
; Line intersects the plane.
Return True
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function clips the specified polygon with the planes you have created.
; The original polygon's data is overwritten with the new clipped polygon.
;
; If the resulting polygon has 0 vertices, then the polygon was completely outside the region bounded by the clipping planes.
;
; Note:
; You can even call this function with a single clipping plane specified, and the polygon will be cut by that plane.
; The half which was on the inside side of the plane will be the polygon that is returned.
;
; The Fast flag allows you to enable to disable the interpolation of vertex appearance information.
; In other words, the final output polygon will have incorrect colors, normals, texture coordinates, and alpha.
; Even the original vertices will have these properties wiped out.
; The positions, however, will be correct.
;
; FAST mode is intended for use when you need to test to see if a polygon is in a frustum, but you don't care if those other
; properties are interpolated.
;
; You should also call CLIP_FastPolyInFrustum() before calling this function to check to see if the polygon is wholly outside
; the frustum, and should not be clipped at all.
;
; IMPORTANT NOTE!
; There may be a bug with interpolating UV coordinates in this function, or in the InterpolatedVertex function.
; I was getting some UV glitches and I cannot find the bug in these two functions, if there even is one.
; All other interpolations seem to work fine.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_ClipPoly(POLY_Clip.CLIP_Poly, Fast=False)
Local POLY_Input.CLIP_Poly, POLY_Output.CLIP_Poly, POLY_Swap.CLIP_Poly
Local LOOP_Plane.CLIP_Plane
Local LOOP_Vertex
Local V1_Index, V2_Index, VI_Index, VN_Index
Local V1_Inside, V2_Inside
Local Vertices
; Set up the input/output buffer pointers.
POLY_Input = POLY_Clip
POLY_Output = POLY_Temp
; For each clipping plane...
For LOOP_Plane = Each CLIP_Plane
; Clear all vertcies from the output polygon.
POLY_Output\Vertices = 0
; Is the first vertex on the backside of the clipping plane?
V1_Inside = CLIP_Vertex_Inside_Plane(POLY_Input, 0, LOOP_Plane)
; For each edge in the input polygon...
For LOOP_Vertex = 0 To POLY_Input\Vertices-1
; Calculate the vertices that form this edge.
V1_Index = LOOP_Vertex
V2_Index = LOOP_Vertex+1
If V2_Index = POLY_Input\Vertices Then V2_Index = 0
; Is the endpoint of this edge on the back side of the clipping plane?
V2_Inside = CLIP_Vertex_Inside_Plane(POLY_Input, V2_Index, LOOP_Plane)
Select True
; Output V2.
Case ((V1_Inside=True) And (V2_Inside=True))
; Add V2 (endpoint of edge) to output polygon.
If Fast
; Create a new vertex in the destination polygon and copy only the vertex's position.
VN_Index = POLY_Output\Vertices
POLY_Output\Vertices = POLY_Output\Vertices + 1
POLY_Output\Vx#[VN_Index] = POLY_Input\Vx#[V2_Index]
POLY_Output\Vy#[VN_Index] = POLY_Input\Vy#[V2_Index]
POLY_Output\Vz#[VN_Index] = POLY_Input\Vz#[V2_Index]
Else
; Create a new vertex in the destination polygon and copy all properties.
CLIP_CopyVertex(POLY_Input, V2_Index, POLY_Output)
EndIf
; Output intersection point.
Case ((V1_Inside=True) And (V2_Inside=False))
; Find the point at which the edge intersects this plane.
CLIP_Edge_Intersect_Plane(POLY_Input, V1_Index, V2_Index, LOOP_Plane)
; Add intersection point.
If Fast
VN_Index = POLY_Output\Vertices
POLY_Output\Vertices = POLY_Output\Vertices + 1
POLY_Output\Vx#[VN_Index] = CLIP_Intersect_X#
POLY_Output\Vy#[VN_Index] = CLIP_Intersect_Y#
POLY_Output\Vz#[VN_Index] = CLIP_Intersect_Z#
Else
CLIP_Add_Interpolated_Vertex(POLY_Input, V1_Index, V2_Index, CLIP_Intersect_U#, POLY_Output)
EndIf
; No output.
Case ((V1_Inside=False) And (V2_Inside=False))
; Both vertcies are on the outside side of the plane.
; Don't add any vertices to the polygon.
; Output Intersection point and V2.
Case ((V1_Inside=False) And (V2_Inside=True))
; Find the point at which the edge intersects this plane.
CLIP_Edge_Intersect_Plane(POLY_Input, V1_Index, V2_Index, LOOP_Plane)
; Add intersection point.
If Fast
VN_Index = POLY_Output\Vertices
POLY_Output\Vertices = POLY_Output\Vertices + 1
POLY_Output\Vx#[VN_Index] = CLIP_Intersect_X#
POLY_Output\Vy#[VN_Index] = CLIP_Intersect_Y#
POLY_Output\Vz#[VN_Index] = CLIP_Intersect_Z#
Else
CLIP_Add_Interpolated_Vertex(POLY_Input, V1_Index, V2_Index, CLIP_Intersect_U#, POLY_Output)
EndIf
; Add V2.
If Fast
; Create a new vertex in the destination polygon and copy only the vertex's position.
VN_Index = POLY_Output\Vertices
POLY_Output\Vertices = POLY_Output\Vertices + 1
POLY_Output\Vx#[VN_Index] = POLY_Input\Vx#[V2_Index]
POLY_Output\Vy#[VN_Index] = POLY_Input\Vy#[V2_Index]
POLY_Output\Vz#[VN_Index] = POLY_Input\Vz#[V2_Index]
Else
; Create a new vertex in the destination polygon and copy all properties.
CLIP_CopyVertex(POLY_Input, V2_Index, POLY_Output)
EndIf
End Select
; V2 will be the start of next edge, V1, so since we already checked it, use it's state in the next loop for V1.
V1_Inside = V2_Inside
Next
; If there are no vertices in the final polygon...
If POLY_Output\Vertices = 0
; The polygon has been completely clipped away.
; Delete all vertices from the original polygon, delete the temporary storage buffer, and exit the function early.
POLY_Clip\Vertices = 0
Return
EndIf
; Swap the pointers to the input polygon data and the output polygon data
; This makes the output data from the last loop the input data to the next,
; and uses the old input location to store the new output data.
POLY_Swap = POLY_Output
POLY_Output = POLY_Input
POLY_Input = POLY_Swap
Next
; If we've made it this far, we have a clipped polygon that lies within the frustum!
; Copy the final output over the original polygon data, delete the temporary storage buffer, and exit the function.
; (We swapped input and output at the end of the last loop, so input really points to the final output.)
CLIP_CopyPoly(POLY_Input, POLY_Clip, Fast)
Return
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function clips all polygons against the clipping planes. See CLIP_ClipPoly() for more details.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_ClipPolys()
Local ThisPoly.CLIP_Poly
For ThisPoly = Each CLIP_Poly
CLIP_ClipPoly(ThisPoly)
Next
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function copies one polygon to another.
; If fast copy is enabled, only the positions are copied.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CopyPoly.CLIP_Poly(POLY_Src.CLIP_Poly, POLY_Dest.CLIP_Poly, Fast=False)
Local LOOP_Vertex
POLY_Dest\Vertices = POLY_Src\Vertices
If Fast
For LOOP_Vertex = 0 To POLY_Src\Vertices-1
POLY_Dest\Vx#[LOOP_Vertex] = POLY_Src\Vx#[LOOP_Vertex]
POLY_Dest\Vy#[LOOP_Vertex] = POLY_Src\Vy#[LOOP_Vertex]
POLY_Dest\Vz#[LOOP_Vertex] = POLY_Src\Vz#[LOOP_Vertex]
Next
Else
For LOOP_Vertex = 0 To POLY_Src\Vertices-1
POLY_Dest\Vx#[LOOP_Vertex] = POLY_Src\Vx#[LOOP_Vertex]
POLY_Dest\Vy#[LOOP_Vertex] = POLY_Src\Vy#[LOOP_Vertex]
POLY_Dest\Vz#[LOOP_Vertex] = POLY_Src\Vz#[LOOP_Vertex]
POLY_Dest\Vnx#[LOOP_Vertex] = POLY_Src\Vnx#[LOOP_Vertex]
POLY_Dest\Vny#[LOOP_Vertex] = POLY_Src\Vny#[LOOP_Vertex]
POLY_Dest\Vnz#[LOOP_Vertex] = POLY_Src\Vnz#[LOOP_Vertex]
POLY_Dest\Vr#[LOOP_Vertex] = POLY_Src\Vr#[LOOP_Vertex]
POLY_Dest\Vg#[LOOP_Vertex] = POLY_Src\Vg#[LOOP_Vertex]
POLY_Dest\Vb#[LOOP_Vertex] = POLY_Src\Vb#[LOOP_Vertex]
POLY_Dest\Va#[LOOP_Vertex] = POLY_Src\Va#[LOOP_Vertex]
POLY_Dest\Vu0#[LOOP_Vertex] = POLY_Src\Vu0#[LOOP_Vertex]
POLY_Dest\Vv0#[LOOP_Vertex] = POLY_Src\Vv0#[LOOP_Vertex]
POLY_Dest\Vu1#[LOOP_Vertex] = POLY_Src\Vu1#[LOOP_Vertex]
POLY_Dest\Vv1#[LOOP_Vertex] = POLY_Src\Vv1#[LOOP_Vertex]
Next
EndIf
Return POLY_Dest
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function interpolates between two values.
;
; In other words, it takes two numbers, and calculates a number that is somewhere between them.
;
; A# and B# are the two numbers to interpolate between.
; Weight# is how much each affects the final output.
;
; In other words, a weight of 0 will return A#, and a weight of 1 will return B#.
; And a weight of 0.5 will give you a value halfway between them.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Interpolate#(A#, B#, Weight#)
Return (A#*(1.0-Weight#) + B#*Weight#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function linearly interpolates a normal.
;
; In other words, it takes two normals, and calculates a normal that is somewhere between them.
; It uses a linear interpolation, so it is slightly inaccurate, but for most things it will be good enough.
;
; N1xyz and N2xyz are the two normals to interpolate between.
; Weight# is how much each affects the final output.
;
; In other words, a weight of 0.5 will give you a normal halfway between them. A weight of 0.25 will give you a normal which is
; more like the first. And a weight of 1.0 will give you a normal which is exactly the same as Normal 2.
;
; The interpolated normal is returned in CLIP_Normal_X#, CLIP_Normal_Y#, and CLIP_Normal_Z#
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_InterpolateNormal(N1x#, N1y#, N1z#, N2x#, N2y#, N2z#, Weight#)
; Calculate interpolated normal.
CLIP_Normal_X# = N1x#*(1.0-Weight#) + N2x#*Weight#
CLIP_Normal_Y# = N1y#*(1.0-Weight#) + N2y#*Weight#
CLIP_Normal_Z# = N1z#*(1.0-Weight#) + N2z#*Weight#
; Renormalize. (Make normal's length = 1)
Length# = Sqr(CLIP_Normal_X#*CLIP_Normal_X# + CLIP_Normal_Y#*CLIP_Normal_Y# + CLIP_Normal_Z#*CLIP_Normal_Z#)
If Length# > 0
CLIP_Normal_X# = CLIP_Normal_X# / Length#
CLIP_Normal_Y# = CLIP_Normal_Y# / Length#
CLIP_Normal_Z# = CLIP_Normal_Z# / Length#
Else
CLIP_Normal_X# = 0
CLIP_Normal_Y# = 0
CLIP_Normal_Z# = 0
EndIf
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function returns true if the specified vertex of the specified polygon is on the back side of the specified plane.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Vertex_Inside_Plane(Poly.CLIP_Poly, Index, Plane.CLIP_Plane)
Return CLIP_Point_Inside_Plane(Poly\Vx#[Index], Poly\Vy#[Index], Poly\Vz#[Index], Plane\A#, Plane\B#, Plane\C#, Plane\D#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function determines the location along a line where a polygon edge, defined by two vertices, intersects a clipping plane.
; V1 and V2 are the indices of the vertcies in the specified polygon.
; Returns the location of the intersetion in CLIP_Intersect_XYZ# and CLIP_Intersect_U#
; Returns true if an intersection actually occured.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Edge_Intersect_Plane(Poly.CLIP_Poly, V1, V2, Plane.CLIP_Plane)
Return CLIP_Line_Intersect_Plane(Poly\Vx#[V1], Poly\Vy#[V1], Poly\Vz#[V1], Poly\Vx#[V2], Poly\Vy#[V2], Poly\Vz#[V2], Plane\A#, Plane\B#, Plane\C#, Plane\D#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function copies the specified vertex from the specified polygon to the specified polygon,
; and returns the index of the new vertex.
;
; If FAST is enabled, only the vertex's position will be copied to the new vertex.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CopyVertex(POLY_Src.CLIP_Poly, Src_Index, POLY_Dest.CLIP_Poly, Fast=False)
Local Dest_Index
Dest_Index = CLIP_AddVertex(POLY_Dest)
If Fast
POLY_Dest\Vx#[Dest_Index] = POLY_Src\Vx#[Src_Index]
POLY_Dest\Vy#[Dest_Index] = POLY_Src\Vy#[Src_Index]
POLY_Dest\Vz#[Dest_Index] = POLY_Src\Vz#[Src_Index]
Else
POLY_Dest\Vx#[Dest_Index] = POLY_Src\Vx#[Src_Index]
POLY_Dest\Vy#[Dest_Index] = POLY_Src\Vy#[Src_Index]
POLY_Dest\Vz#[Dest_Index] = POLY_Src\Vz#[Src_Index]
POLY_Dest\Vnx#[Dest_Index] = POLY_Src\Vnx#[Src_Index]
POLY_Dest\Vny#[Dest_Index] = POLY_Src\Vny#[Src_Index]
POLY_Dest\Vnz#[Dest_Index] = POLY_Src\Vnz#[Src_Index]
POLY_Dest\Vr#[Dest_Index] = POLY_Src\Vr#[Src_Index]
POLY_Dest\Vg#[Dest_Index] = POLY_Src\Vg#[Src_Index]
POLY_Dest\Vb#[Dest_Index] = POLY_Src\Vb#[Src_Index]
POLY_Dest\Va#[Dest_Index] = POLY_Src\Va#[Src_Index]
POLY_Dest\Vu0#[Dest_Index] = POLY_Src\Vu0#[Src_Index]
POLY_Dest\Vv0#[Dest_Index] = POLY_Src\Vv0#[Src_Index]
POLY_Dest\Vu1#[Dest_Index] = POLY_Src\Vu1#[Src_Index]
POLY_Dest\Vv1#[Dest_Index] = POLY_Src\Vv1#[Src_Index]
EndIf
Return Dest_Index
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function adds a new vertex to the specified polygon.
; It's properties are calculated by interpolating between V1 annd V2 of the specified polygon, using the specified weighting value.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Add_Interpolated_Vertex(POLY_Src.CLIP_Poly, Vertex1, Vertex2, Weight#, POLY_Dest.CLIP_poly)
Local Vertex_I
Local X#, Y#, Z#
Local R#, G#, B#, A#
Local U0#, V0#, U1#, V1#
Local Nx#, Ny#, Nz#
; Create the new vertex.
Vertex_I = CLIP_AddVertex(POLY_Dest)
; Calculate the interpolated properties of the vertex.
X# = CLIP_Interpolate(POLY_Src\Vx#[Vertex1], POLY_Src\Vx#[Vertex2], Weight#)
Y# = CLIP_Interpolate(POLY_Src\Vy#[Vertex1], POLY_Src\Vy#[Vertex2], Weight#)
Z# = CLIP_Interpolate(POLY_Src\Vz#[Vertex1], POLY_Src\Vz#[Vertex2], Weight#)
R# = CLIP_Interpolate(POLY_Src\Vr#[Vertex1], POLY_Src\Vr#[Vertex2], Weight#)
G# = CLIP_Interpolate(POLY_Src\Vg#[Vertex1], POLY_Src\Vg#[Vertex2], Weight#)
B# = CLIP_Interpolate(POLY_Src\Vb#[Vertex1], POLY_Src\Vb#[Vertex2], Weight#)
A# = CLIP_Interpolate(POLY_Src\Va#[Vertex1], POLY_Src\Va#[Vertex2], Weight#)
U0# = CLIP_Interpolate(POLY_Src\Vu0#[Vertex1], POLY_Src\Vu0#[Vertex2], Weight#)
V0# = CLIP_Interpolate(POLY_Src\Vv0#[Vertex1], POLY_Src\Vv0#[Vertex2], Weight#)
U1# = CLIP_Interpolate(POLY_Src\Vu1#[Vertex1], POLY_Src\Vu1#[Vertex2], Weight#)
V1# = CLIP_Interpolate(POLY_Src\Vv1#[Vertex1], POLY_Src\Vv1#[Vertex2], Weight#)
CLIP_InterpolateNormal(POLY_Src\Vnx#[Vertex1], POLY_Src\Vny#[Vertex1], POLY_Src\Vnz#[Vertex1], POLY_Src\Vnx#[Vertex2], POLY_Src\Vny#[Vertex2], POLY_Src\Vnz#[Vertex2], Weight#)
Nx# = CLIP_Normal_X#
Ny# = CLIP_Normal_Y#
Nz# = CLIP_Normal_Z#
; Set the properties of the new vertex.
CLIP_SetVertexPosition(POLY_Dest, Vertex_I, X#, Y#, Z#)
CLIP_SetVertexColor(POLY_Dest, Vertex_I, R#, G#, B#)
CLIP_SetVertexAlpha(POLY_Dest, Vertex_I, A#)
CLIP_SetVertexUV(POLY_Dest, Vertex_I, U0#, V0#, 0)
CLIP_SetVertexUV(POLY_Dest, Vertex_I, U1#, V1#, 1)
CLIP_SetVertexNormal(POLY_Dest, Vertex_I, Nx#, Ny#, Nz#)
; Return the index number of the next vertex.
Return Vertex_I
End Function
; -------------------------------------------------------------------------------------------------------------------
; This function calculates the plane equation for a triangle.
; It returns the results in the global variables CLIP_A#, CLIP_B#, CLIP_C#, and CLIP_D#.
;
; ABC is the triangle's normal. D is the distance of the plane from the origin. Distance is negative if the normal
; points away from the origin, and positive if it points toward it.
;
; The normal points in the direction the triangle is facing.
; Wind vertices clockwise to have normal point towards you.
;
; In other words, a triangle aligned with the X, Z axis, wound counterclockwise when looking down, at a height of 5,
; will have a normal pointing downwards, and a value for D# of 5.
; -------------------------------------------------------------------------------------------------------------------
Function CLIP_CalculateTriPlane(V1x#, V1y#, V1z#, V2x#, V2y#, V2z#, V3x#, V3y#, V3z#)
Local Px#, Py#, Pz#
Local Qx#, Qy#, Qz#
Local Nx#, Ny#, Nz#, Nl#
; Create two vectors from the sides of the triangle.
Px# = V1x#-V3x#
Py# = V1y#-V3y#
Pz# = V1z#-V3z#
Qx# = V2x#-V3x#
Qy# = V2y#-V3y#
Qz# = V2z#-V3z#
; Compute their cross product.
Nx# = (Py#*Qz#) - (Qy#*Pz#)
Ny# = (Pz#*Qx#) - (Qz#*Px#)
Nz# = (Px#*Qy#) - (Qx#*Py#)
; Calculate the length of the vector.
Nl# = Sqr(Nx#*Nx# + Ny#*Ny# + Nz#*Nz#)
; Calculate the plane equation for the triangle.
; ABC is the triangle's normal.
; Normalize the vector so it has a length of 1.
; This is the normal of the triangle.
CLIP_A# = Nx# / Nl#
CLIP_B# = Ny# / Nl#
CLIP_C# = Nz# / Nl#
; Calculate minimum distance of plane the triangle lies in, from the origin.
; This is the shortest distance to the surface of the plane from 0,0,0.
CLIP_D# = -(CLIP_A#*V1x# + CLIP_B#*V1y# + CLIP_C#*V1z#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function calculates the equation of a 2D line.
;
; The equation of a 2D line is the same as the equation of a plane, except that the C component (Normal Z) is assumed to be 0.
; If facing down the line from point 1 to point 2, the line's normal will point left.
; In other words, if the line is an edge of a triangle wound clockwise, the resulting edge normals will point outwards.
;
; Function assumes positive Y is up, unlike screen coordinates.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_Calculate2DLine(X1#, Y1#, X2#, Y2#)
Local Nx#, Ny#, Nl#
; Calculate the normal of the line, (A = Nx, B = Ny) and the distance of the line (D) from the origin (0,0,0).
Nx# = Y2# - Y1#
Ny# = X1# - X2#
; Normalize the normal.
Nl# = Sqr(Nx#*Nx# + Ny#*Ny#)
CLIP_A# = Nx# / Length#
CLIP_B# = Ny# / Length#
CLIP_D# = -(CLIP_A#*X1# + CLIP_B#*Y1#)
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function determines if a circle is intersecting a line, or on the inside side of a line.
;
; XY is the position of the circle.
; Radius is the circle's radius.
; ABD is the equation of the line.
; -----------------------------------------------------------------------------------------------------------------------------------
Function CLIP_CircleInsideLine(X#, Y#, Radius#, A#, B#, D#)
If (X#*A# + Y#*B# + D#) < Radius# Then Return True
Return False
End Function
; -----------------------------------------------------------------------------------------------------------------------------------
; This function determines if a circle is intersecting/inside a triangle, in 2D.
;
; XY is the position of the circle.
; Radius is the circle's radius.
; Vx, Vy are the vertices of the triangle, wound in clockwise order.
; -----------------------------------------------------------------------------------------------------------------------------------
;Function CLIP_CircleInsideTri(X#, Y#, Radius#, Vx1#, Vy1#, Vx2#, Vy2#, Vx3#, Vy3#)
; If the circle is intersecting or on the inside side
;End Function
; -------------------------------------------------------------------------------------------------------------------
; This function returns the X axis scale of an entity, as set by ScaleEntity().
; -------------------------------------------------------------------------------------------------------------------
Function CLIP_EntityScaleX#(Entity)
Vx# = GetMatElement(Entity, 0, 0)
Vy# = GetMatElement(Entity, 0, 1)
Vz# = GetMatElement(Entity, 0, 2)
Scale# = Sqr(Vx#*Vx# + Vy#*Vy# + Vz#*Vz#)
Return Scale#
End Function
; -------------------------------------------------------------------------------------------------------------------
; This function returns the Y axis scale of an entity, as set by ScaleEntity().
; -------------------------------------------------------------------------------------------------------------------
Function CLIP_EntityScaleY#(Entity)
Vx# = GetMatElement(Entity, 1, 0)
Vy# = GetMatElement(Entity, 1, 1)
Vz# = GetMatElement(Entity, 1, 2)
Scale# = Sqr(Vx#*Vx# + Vy#*Vy# + Vz#*Vz#)
Return Scale#
End Function
; -------------------------------------------------------------------------------------------------------------------
; This function returns the Z axis scale of an entity, as set by ScaleEntity().
; -------------------------------------------------------------------------------------------------------------------
Function CLIP_EntityScaleZ#(Entity)
Vx# = GetMatElement(Entity, 2, 0)
Vy# = GetMatElement(Entity, 2, 1)
Vz# = GetMatElement(Entity, 2, 2)
Scale# = Sqr(Vx#*Vx# + Vy#*Vy# + Vz#*Vz#)
Return Scale#
End Function
Free = Don't email me for support. I'm very busy!
Buy a copy of my shadow system if you want help with using it. :-)