[bb] Lotus Particle System R2 - Part 1 by N [ 1+ years ago ]

Started by BlitzBot, June 29, 2017, 00:28:43

Previous topic - Next topic

BlitzBot

Title : Lotus Particle System R2 - Part 1
Author : N
Posted : 1+ years ago

Description : This is part 1 of the source code (since it's too large to go into one entry, as Rob pointed out).  For part 2: <a href="codearcs62a3.html?code=1657" >Lotus Particle System R2 - Part 2</a>

In the interest of furthering the potential usefulness of Lotus R2 (I will try to document some of it later, just don't expect it overnight), I'm releasing it into the public domain.

Hopefully this will help those people who are particularly hateful of licenses (can't blame'em considering I loathe anything longer than 100 lines).

Anywho, feel free to use and abuse.  I'll add a comment when I begin documenting the source.  (No guarantee that it will work with the DIMs arranged in the order they're in, however I don't think there will be a problem with them).

Media for Lotus R2 is laid out like so:
Code: BASIC
particles.png
_________________
| 0 | 1 | 2 | 3 |
|___|___|___|___|
| 4 | 5 | 6 | 7 |
|___|___|___|___|

Where numbers indicate the indices of particle cells (textures).  These cells are individual particles or animation frames (depending on which Load function you use).

The Graph functionality allows you to have keyframe'd values (color and size were all that were finished last I checked) instead of linearly interpolating between two values.

The public domain license does not apply to the existing archive of Lotus R2.  That is to say, all media, samples, the editor, etc. are still under the license they were originally released under. [/i]

Code :
Code: blitzbasic
Dim gSine#(0)
Dim gCosine#(0)
Dim gGraphArray#( 0, 1 )
Dim gAlphaPartArray#( 0, 0 )
Dim gLotusUpdateTimes%( 5 )

Function Min#(A#,B#)
	If A < B Then Return B
	Return A
End Function

Function Max#(A#,B#)
	If A > B Then Return B
	Return A
End Function

Function lSort( L, R )
	
	If R <= L Then Return False
	
	Local A, B, SwapA#, SwapB#, Middle#
	A = L
	B = R
	
	Middle# = gAlphaPartArray( (L+R)/2, 0 )
	
	Repeat
		
		While gAlphaPartArray( A, 0 ) < Middle
			A = A + 1
			If A > R Then Exit
		Wend
		
		While  Middle < gAlphaPartArray( B, 0 )
			B = B - 1
			If B < 0 Then Exit
		Wend
		
		If A > B Then Exit
		
		SwapA = gAlphaPartArray( A, 0 )
		SwapB = gAlphaPartArray( A, 1 )
		gAlphaPartArray( A, 0 ) = gAlphaPartArray( B, 0 )
		gAlphaPartArray( A, 1 ) = gAlphaPartArray( B, 1 )
		gAlphaPartArray( B, 0 ) = SwapA
		gAlphaPartArray( B, 1 ) = SwapB
		
		A = A + 1
		B = B - 1
		
		If B < 0 Then Exit
		
	Forever
	
	If L < B Then lSort( L, B )
	If A < R Then lSort( A, R )
End Function

Function InsertionSort( Size% )
	Local i, j, index
	
	For i = 1 To Size - 1
		index = gGraphArray( i, 0 )
		j = i
		While j > 0 And gGraphArray( j-1, 0 ) > index
			gGraphArray( j, 0 ) = gGraphArray( j - 1, 0 )
			j = j - 1
		Wend
		gGraphArray( j, 0 ) = index
	Next
End Function


;; Line Helper functions, written by Jeremy Alessi (they are public domain)
Function ReturnedY#(x#, X1#, Y1#, X2#, Y2#)
	Return (  Slope( X1#, Y1#, X2#, Y2# ) * x# + YIntercept( X1#, Y1#, X2#, Y2# ) )
End Function

Function Slope#(X1#, Y1#, X2#, Y2#)
	m# = ( ( Y2# - Y1# ) / ( X2# - X1# ) )

	If m#=0
		Return .01 ;avoid infinity
	EndIf
	
	Return m#
End Function

Function YIntercept(X1#, Y1#, X2#, Y2#)
	Return (Y1# - Slope#( X1#, Y1#, X2#, Y2# ) * X1#)
End Function

Type LotusParticle
	Field Texture.LotusTexture
	Field Frame%
	Field FrameStart%
	Field FrameLength%
	Field Animated%
	
	Field Parent.LotusEmitter
	Field Child.LotusEmitter
	Field Trail.LotusEmitter
	
	Field LastPositionX#
	Field LastPositionY#
	Field LastPositionZ#
	
	Field PositionX#
	Field PositionY#
	Field PositionZ#
	
	Field TranslationX#
	Field TranslationY#
	Field TranslationZ#
	
	Field VelocityX#
	Field VelocityY#
	Field VelocityZ#
	
	Field OVelocityX#
	Field OVelocityY#
	Field OVelocityZ#
	
	Field AccelerationX#
	Field AccelerationY#
	Field AccelerationZ#
	
	Field VelocityDecay#
	
	Field AngleX#
	Field AngleY#
	Field AngleZ#
	
	Field AngleVelocityX#
	Field AngleVelocityY#
	Field AngleVelocityZ#
	
	Field AngleAccelerationX#
	Field AngleAccelerationY#
	Field AngleAccelerationZ#
	
	Field DeflectorSpeedX#
	Field DeflectorSpeedY#
	Field DeflectorSpeedZ#
	
	Field RedFrom%
	Field GreenFrom%
	Field BlueFrom%
	Field AlphaFrom#
	
	Field RedTo%
	Field GreenTo%
	Field BlueTo%
	Field AlphaTo#
	
	Field ColorGraph.LotusGraph
	
	Field SizeFromX#
	Field SizeFromY#
	Field SizeFromZ#
	
	Field SizeToX#
	Field SizeToY#
	Field SizeToZ#
	
	Field SizeGraph.LotusGraph
	
	Field WaveRadiusX#
	Field WaveRadiusY#
	Field WaveRadiusZ#
	
	Field WaveSpeedX#
	Field WaveSpeedY#
	Field WaveSpeedZ#
	
	Field BlendMode%
	
	Field Vertex%
	
	Field RollMode%
	
	Field LifeSpan#
	Field LifeBegan#
	Field Life#
	Field ParticleMesh%
	Field Previous.LotusParticle
	
	Field GravityEnabled%
	Field Gravity#
	Field Weight#
	
	Field Range#
	
	Field ViewMode%
	Field LifeMode%
	
	Field ChildMode%
	Field Frozen%
	Field Hidden%
	Field Draw%
	Field Cull%
	Field Sorting%
	
	Field Bounce%
	Field BounceDecay#
	Field BounceMax%
	Field Bounces%
	
	Field MinY#
	
	Field BounceSound%
	Field BounceSoundChannel%
	Field BounceSoundRange#
	
	Field SplineMesh%
	
	Field DeflectorsAffect%
End Type

Type LotusEmitter
	Field Name$

	Field Entity%
	Field Texture.LotusTexture
	Field Frame%
	Field FrameStart%
	Field FrameLength%
	Field Animated%

	Field Parent.LotusEmitter
	Field Child.LotusEmitter
	Field Trail.LotusEmitter
	
	Field TranslationJitterUp%
	Field TranslationJitterDown%
	
	Field PositionX#
	Field PositionY#
	Field PositionZ#
	
	Field AngleX#
	Field AngleY#
	Field AngleZ#
	
	Field TranslationJitterX#
	Field TranslationJitterY#
	Field TranslationJitterZ#
	
	Field VelocityJitterUp
	Field VelocityJitterDown
	
	Field VelocityJitterX#
	Field VelocityJitterY#
	Field VelocityJitterZ#
	
	Field VelocityDecay#
	
	Field TranslationX#
	Field TranslationY#
	Field TranslationZ#
	
	Field VelocityX#
	Field VelocityY#
	Field VelocityZ#
	
	Field AccelerationX#
	Field AccelerationY#
	Field AccelerationZ#
	
	Field AngleVelocityX#
	Field AngleVelocityY#
	Field AngleVelocityZ#
	
	Field AngleAccelerationX#
	Field AngleAccelerationY#
	Field AngleAccelerationZ#
	
	Field RandomRotationX#
	Field RandomRotationY#
	Field RandomRotationZ#
	
	Field CircleRadiusX#
	Field CircleSpeedX#
	Field CircleRadiusY#
	
	Field CircleSpeedY#
	Field CircleRadiusZ#
	Field CircleSpeedZ#
	
	Field RedFrom%
	Field GreenFrom%
	Field BlueFrom%
	Field AlphaFrom#
	
	Field RedTo%
	Field GreenTo%
	Field BlueTo%
	Field AlphaTo#
	
	Field ColorJitterRed%
	Field ColorJitterGreen%
	Field ColorJitterBlue%
	Field ColorJitterAlpha#
	Field ColorJitterUniform%
	Field ColorJitterUp%
	Field ColorJitterDown%
	
	Field ColorGraph.LotusGraph
	
	Field SizeJitterX#
	Field SizeJitterY#
	Field SizeJitterZ#
	Field SizeJitterUniform%
	Field SizeJitterUp%
	Field SizeJitterDown%
	
	Field SizeFromX#
	Field SizeFromY#
	Field SizeFromZ#
	
	Field SizeToX#
	Field SizeToY#
	Field SizeToZ#
	
	Field SizeGraph.LotusGraph
	
	Field CylinderX#
	Field CylinderY#
	Field CylinderZ#
	
	Field CubeX#
	Field CubeY#
	Field CubeZ#
	
	Field WaveRadiusX#
	Field WaveRadiusY#
	Field WaveRadiusZ#
	
	Field WaveSpeedX#
	Field WaveSpeedY#
	Field WaveSpeedZ#
	
	Field BlendMode%
	
	Field LifeSpan%
	Field LifeSpanJitter%
	Field LifeSpanJitterUp%
	Field LifeSpanJitterDown%
	
	Field Active%
	Field ActiveSpan%
	Field FreeOnEndActive%
	
	Field GravityEnabled%
	Field Gravity#
	Field GravityJitter#
	Field GravityJitterUp%
	Field GravityJitterDown%
	Field Weight#
	
	Field RollMode%
	
	Field Emit%
	Field EmissionRate%
	
	Field InnerRadius#
	Field Radius#
	Field YRadius#
	
	Field ParticleMesh%
	Field Latest.LotusParticle
	Field ViewMode%
	Field LifeMode%
	Field WaitA#		;; Auto-emission wait
	Field WaitB#		;; Child-emission wait
	Field WaitC#		;; Trail-emission wait
	Field WaitSpan%
	Field ChildMode%
	Field Range#
	
	Field Frozen%
	Field Hidden%
	Field Cull%
	Field Sorting%
	Field DWaitSpan%
	Field WaitSpanJitter%
	
	Field Bounce%
	Field BounceDecay#
	Field BounceMax%
	
	Field MinY#
	
	Field EmitSound%
	Field BounceSound%
	Field LoopEmitSound%
	Field EmitSoundChannel%
	Field EmitSoundRange#
	Field BounceSoundRange#
	
	Field SplineMesh%
	
	Field DeflectorsAffect%
End Type

Type LotusDeflector
	Field PositionX#
	Field PositionY#
	Field PositionZ#
	Field Entity%
	Field Radius#
	Field Strength#
	Field Active%
End Type

Type LotusTexture
	Field Bitmap%
	Field Flags%
	Field Path$
	Field Add%
	Field Multiply%
	Field Alpha%
	Field UStep#
	Field VStep#
	Field Rows%
	Field Columns%
End Type

Type LotusGraph
	Field Bank%
	Field Keys%
	Field Width#
End Type

Dim LoadedEmitters%(255)						;; The emitters loaded by LoadASCIIEmitters
Global gLoadedEmittersCount%					;; The amount of emitters loaded through LoadASCIIEmitters

Dim LoadedDeflectors%(255)					;; The deflectors loaded by LoadASCIIEmitters
Global gLoadedDeflectorsCount%				;; The amount of deflectors loaded through LoadASCIIEmitters

Dim LoadedTextures%(255)						;; The textures loaded by LoadASCIIEmitters
Global gLoadedTexturesCount%					;; The amount of textures loaded through LoadASCIIEmitters

Global gLotusParticlePivot%					;; Pivot used to determine various properties and the position and rotation of particles
Global gLotusTPivot%						;; Extra pivot used for view mode calculations
Global gLotusParticleMesh%					;; The container-mesh for all Lotus particles
Global gLotusCamera%						;; The camera particles will face (when told to)

Global gLotusNullTexture.LotusTexture			;; The 'Null Texture' object- used in the case that no texture is available
Global gLotusEmitterTexture%					;; The texture assigned to emitter cones.
Global gNullTexture%						;; The handle of the 'Null Texture'

Global gLotusParticleCount%					;; The amount of particles in existence
Global gLotusAlphaParticleCount%				;; The amount of alpha-blended particles to be sorted
Global gLotusParticlesDrawn%					;; The amount of particles drawn during the last call to UpdateLotusParticles

Const cP_QUAD% = 0							;; SetEmitterParticleMesh enumerator; sets a particle's mesh to a quad (two triangles)
Const cP_TRIANGLE% = 1						;; SetEmitterParticleMesh enumerator; sets a particle's mesh to a triangle
Const cP_TRAIL% = 2							;; SetEmitterParticleMesh enumerator; sets a particle's mesh to the trail style (all particles are 'connected' by quads)
Const cP_TRAILVERTICAL% = 3					;; SetEmitterParticleMesh enumerator; sets a particle's mesh to the vertical trail style (all particles are 'connected' by quads)
Const cP_DENT% = 4							;; SetEmitterParticleMesh enumerator; sets a particle's mesh to a quad with a dent in the center (four triangles)

Const updTimeSort% = 0						;; Indices for update times
Const updTimeEmit% = 1
Const updTimePart% = 2
Const updTimeDrawAlpha% = 3
Const updTimeTexture% = 4
Const updTimeAll% = 5

Global gWidth%									;; The screen buffer width and height
Global gHeight%

Const cUSE_EMITTERCONES = 0						;; Whether or not to use emitter cones (little graphical thingy); recommended to leave off

Global gFacingX#,gFacingY#,gFacingZ#				;; Facing vector

Type LotusVector
	Field X#
	Field Y#
	Field Z#
End Type

Global gTempLotusVector.LotusVector	;can be used for temporary LotusVector operations.
Global gNullLotusVector.LotusVector	;zero-LotusVector.

Type LotusStringPiece
	Field Text$
End Type

Function DivideString(Text$,Sep$)
	Text$ = Trim(Text$)
	Local Pieces = 0
	OT$ = Text$
	Text$ = ""
	For E = 1 To Len(OT)
		C = Asc(Mid(OT,E,1))
		S = Instr(Sep,Chr(C))

		If (Not StringOpen) And C = 39 Then Exit

		If C = 34 Then StringOpen = Not StringOpen

		If (S > 0 Or C = 32) And (Not StringOpen) Then
			Text = Text + Chr(4)
		Else
			Text = Text + Chr(C)
		EndIf
	Next

	While Text$ <> ""
		If Asc(Left(Text$,1)) = 34 Then
			Text$ = Right(Text$,Len(Text$)-1)
			Closest = Instr(Text$,Chr(34))
		Else
			Closest = Instr(Text$,Chr(4))
		EndIf

		If Closest Then
			NText$ = Trim(Left(Text$,Closest-1))
			Text$ = Trim(Right(Text$,Len(Text$)-Closest))
		Else
			NText$ = Text$
			Text$ = ""
		EndIf

		P.LotusStringPiece = New LotusStringPiece
		PText$ = Replace(NText$,""+Chr(34),Chr(34))
		Pieces = Pieces + 1
	Wend

	Return Pieces
End Function

;creates a LotusVector and returns it
Function LotusVec.LotusVector(X#=0,Y#=0,Z#=0)
	V.LotusVector = New LotusVector
	VX = X
	VY = Y
	V = Z
	Return V
End Function

;adds LotusVector B to LotusVector A
Function LotusVec_Add(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	AX = AX + BX
	AY = AY + BY
	A = A + B
	Return True
End Function

;subtracts LotusVector B from LotusVector A
Function LotusVec_Subtract(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	AX = AX - BX
	AY = AY - BY
	A = A - B
	Return True
End Function

;returns the difference of LotusVector A and LotusVector B
Function LotusVec_Difference.LotusVector(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return Null
	Return LotusVec(AX-BX,AY-BY,A-B)
End Function

;returns the sum of LotusVector A and LotusVector B
Function LotusVec_Sum.LotusVector(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return Null
	Return LotusVec(AX+BX,AY+BY,A+B)
End Function

;multiplies LotusVector A by LotusVector B
Function LotusVec_Multiply(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	AX = AX * BX
	AY = AY * BY
	A = A * B
	Return True
End Function

;divides LotusVector A by LotusVector B
Function LotusVec_Divide(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	AX = AX / BX
	AY = AY / BY
	A = A / B
	Return True
End Function

;scales LotusVector A by Scalar B
Function LotusVec_Scale(A.LotusVector, B#)
	If Not A <> Null Then Return False
	AX = AX * B
	AY = AY * B
	A = A * B
	Return True
End Function

;divides LotusVector A by Scalar B
Function LotusVec_SDivide(A.LotusVector,B#)
	If Not A <> Null Or B = 0 Then Return False
	AX = AX / B
	AY = AY / B
	A = A / B
	Return True
End Function

;makes LotusVector A the cross product of LotusVectors A and B
Function LotusVec_CrossProduct(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	X# = AY*B - A*BY
	Y# = A*BX - AX*B
	Z# = AX*BY - AY*BX
	AX = X
	AY = Y
	A = Z
	Return True
End Function

;returns the dot product of LotusVectors A and B
Function LotusVec_DotProduct#(A.LotusVector, B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	Return AX * BX + AY * BY + A * B;
End Function

;copies the contents of LotusVector A to a new LotusVector and returns it
Function LotusVec_Copy.LotusVector(A.LotusVector)
	If Not A <> Null Then Return Null
	B.LotusVector = New LotusVector
	BX = AX
	BY = AY
	B = A
	Return B
End Function

;copies the contents of LotusVector B to LotusVector A
Function LotusVec_CopyTo(A.LotusVector,B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	AX = BX
	AY = BY
	A = B
End Function

;normalizes LotusVector A
Function LotusVec_Normalize(A.LotusVector)
	If Not A <> Null Then Return False
	M# = LotusVec_Magnitude(A)
	AX = AX / M
	AY = AY / M
	A = A / M
	Return True
End Function

;returns the magnitude of LotusVector A
Function LotusVec_Magnitude#(A.LotusVector)
	If Not A <> Null Then Return False
	Return Sqr(AX*AX+AY*AY+A*A)
End Function

;returns the distance between LotusVector A and LotusVector B
Function LotusVec_Distance#(A.LotusVector,B.LotusVector)
	If Not A <> Null Or B <> Null Then Return False
	DX# = AX - BX
	DY# = AY - BY
	DZ# = A - B
	Return Sqr(DX*DX+DY*DY+DZ*DZ)
End Function

;inverts LotusVector A
Function LotusVec_Invert(A.LotusVector)
	If Not A <> Null Then Return False
	AX = -AX
	AY = -AY
	A = -A
	Return True
End Function

;returns an inverted LotusVector A
Function LotusVec_Inverse.LotusVector(A.LotusVector)
	If Not A <> Null Then Return Null
	B.LotusVector = LotusVec_Copy(A)
	LotusVec_Invert B
	Return B
End Function

;returns the position of an entity in a LotusVector.  G = Global
Function LotusVec_Entity_Position.LotusVector(Entity,G = False)
	If Entity = 0 Then Return Null
	V.LotusVector = New LotusVector
	VX = EntityX(Entity,G)
	VY = EntityY(Entity,G)
	V = EntityZ(Entity,G)
	Return V
End Function

;returns the angle of an entity in a LotusVector.  G = Global
Function LotusVec_Entity_Angle.LotusVector(Entity,G = False)
	If Entity = 0 Then Return Null
	V.LotusVector = New LotusVector
	VX = EntityPitch(Entity,G)
	VY = EntityYaw(Entity,G)
	V = EntityRoll(Entity,G)
	Return V
End Function

;positions an entity at LotusVector A
Function LotusVec_PositionEntity(Entity,A.LotusVector,Glb=False)
	If Entity = 0 Or A = Null Then Return False
	PositionEntity Entity,AX,AY,A,Glb
End Function

;rotates an entity to LotusVector A
Function LotusVec_RotateEntity(Entity,A.LotusVector,Glb=False)
	If Entity = 0 Or A = Null Then Return False
	RotateEntity Entity,AX,AY,A,Glb
End Function

;turns an entity by LotusVector A
Function LotusVec_TurnEntity(Entity,A.LotusVector)
	If Entity = 0 Or A = Null Then Return False
	TurnEntity Entity,AX,AY,A
End Function

;aligns an entity to LotusVector A
Function LotusVec_AlignToLotusVector(Entity,A.LotusVector,Axes=3,Trans#=1)
	If Entity = 0 Or A = Null Then Return False
	AlignToVector Entity,AX,AY,A,Axes,Trans
End Function

;moves an entity by LotusVector A
Function LotusVec_MoveEntity(Entity,A.LotusVector)
	If Entity = 0 Or A = Null Then Return False
	MoveEntity Entity,AX,AY,A
End Function

;translates an entity by LotusVector A
Function LotusVec_TranslateEntity(Entity,A.LotusVector)
	If Entity = 0 Or A = Null Then Return False
	TranslateEntity Entity,AX,AY,A
End Function

;returns the normals of a vertex
Function LotusVec_VertexNormal.LotusVector(Surface,Index)
	If Surface = 0 Or Index < 0 Or Index > CountVertices(Surface)-1 Then Return Null
	Return LotusVec(VertexNX(Surface,Index),VertexNY(Surface,Index),VertexNZ(Surface,Index))
End Function

;returns the local position of a vertex
Function LotusVec_VertexPosition.LotusVector(Surface,Index)
	If Surface = 0 Or Index < 0 Or Index > CountVertices(Surface)-1 Then Return Null
	Return LotusVec(VertexX(Surface,Index),VertexY(Surface,Index),VertexZ(Surface,Index))
End Function

;sets the position of a vertex to LotusVector A
Function LotusVec_VertexCoords(Surface,Index,A.LotusVector)
	If Surface = 0 Or Index < 0 Or Index > CountVertices(Surface)-1 Or A = Null Then Return False
	VertexCoords Surface,Index,AX,AY,A
End Function

;returns the normal of a triangle
Function LotusVec_TriangleNormal.LotusVector(Surface,Index)
	If Surface = 0 Or Index < 0 Or Index > CountTriangles(Surface)-1 Then Return Null
	Local VNormals.LotusVector[2]
	For N = 0 To 2
			VNormals[N] = LotusVec_VertexNormal(Surface,TriangleVertex(Surface,Index,N))
	Next
	LotusVec_Subtract VNormals[0],VNormals[1]
	LotusVec_Subtract VNormals[1],VNormals[2]
	LotusVec_CrossProduct(VNormals[0],VNormals[1])
	Delete VNormals[1]
	Delete VNormals[2]
	Return VNormals[0]
End Function

;returns the local position of a triangle
Function LotusVec_TrianglePosition.LotusVector(Surface,Index)
	If Surface = 0 Or Index < 0 Or Index > CountTriangles(Surface)-1 Then Return Null
	Local VNormals.LotusVector[2]
	For N = 0 To 2
			VNormals[N] = LotusVec_VertexPosition(Surface,TriangleVertex(Surface,Index,N))
	Next
	LotusVec_Add(VNormals[0],VNormals[1])
	LotusVec_Add(VNormals[0],VNormals[2])
	LotusVec_SDivide(VNormals[0],3)
	Delete VNormals[1]
	Delete VNormals[2]
	Return VNormals[0]
End Function

;transforms LotusVector A from one coordinate system to another
Function LotusVec_TFormPoint(A.LotusVector,EntityA,EntityB)
	If Not A <> Null Then Return False
	TFormPoint AX,AY,A,EntityA,EntityB
End Function

;returns the TFormed vector
Function LotusVec_TFormedA.LotusVector()
	Return LotusVec(TFormedX(),TFormedY(),TFormedZ())
End Function

;puts the values of the TFormed vector into LotusVector A
Function LotusVec_TFormedB(A.LotusVector)
	If A = Null Then Return False
	AX = TFormedX()
	AY = TFormedY()
	A = TFormedZ()
End Function

Global ParticleTiles=0
Global BulletHoleEmitter=0
Global BulletSparkEmitter=0
Global BulletSmokeEmitter=0

Function FXP_SetupTilesets()
	If ParticleTiles = 0 Then
		Tiles = LoadLotusTileset("media/particles.png",59,2,4,1,0,1)
		ParticleTiles = Tiles
	Else
		Tiles = ParticleTiles
	EndIf
	
	Return Tiles
End Function

Function CreateBulletSpark(X#,Y#,Z#,NX#,NY#,NZ#)
	Tiles = FXP_SetupTilesets()
	
	If BulletSparkEmitter = 0 Then
		e = CreateEmitter()
		ApplyTexture e,Tiles,3
		
		SetEmitterVelocity e,0,.2,0
		SetEmitterSizeJitter e,1,0,0,0,1,1
		SetEmitterLifespan e,8
		SetEmitterSorting e,1
		SetEmitterBlend e,3
		SetEmitterColorFrom e,246,167,76,.6
		SetEmitterColorTo e,235,155,0,0
		SetEmitterSizeTo e,1,.5
		SetEmitterSizeFrom e,.5,.25
		SetEmitterRandomRotation e,25,25,0
		SetEmitterRollMode e,1
		SetEmitterEmissionRate e,32
		BulletSparkEmitter = e
	Else
		e = BulletSparkEmitter
	EndIf
	
	If BulletSmokeEmitter = 0 Then
		s = CreateEmitter()
		SetEmitterLifespan s,120
		SetEmitterVelocity s,0,.005,0
		SetEmitterVelocityDecay s,1
		SetEmitterEmissionRate s,4
		SetEmitterColorFrom s,88,86,84,.7
		SetEmitterColorTo s,77,76,75,0
		SetEmitterColorJitter s,15,15,15,0,1
		ApplyTexture s,Tiles,4
		SetEmitterSizeFrom s,0,0
		SetEmitterRandomRotation s,0,0,180
		SetEmitterSizeTo s,1,2
		SetEmitterSizeJitter s,.4,.4,.4,1,1,0
		SetEmitterTranslation s,0,.01,0
		SetEmitterTranslationJitter s,0,.025,0,1,0
		BulletSmokeEmitter = s
	Else
		s = BulletSmokeEmitter
	EndIf
	
	If BulletHoleEmitter = 0 Then
		b = CreateEmitter()
		SetEmitterLifespan b,3000
		SetEmitterViewmode b,2
		SetEmitterColorFrom b,0,0,0,8
		SetEmitterColorTo b,0,0,0,0
		SetEmitterSize b,1,1,1
		SetEmitterRandomRotation b,0,0,180
		SetEmitterSizeJitter b,.4,.4,.4,1,1,1
		ApplyTexture b,Tiles,1
	Else
		b = BulletHoleEmitter
	EndIf
	
	PositionEntity e,X,Y,Z
	PositionEntity s,X,Y,Z
	AlignToVector e,NX,NY,NZ,2,1
	AlignToVector s,NX,NY,NZ,3,1
	MoveEntity s,0,0,.7
	MoveEntity e,0,0,.2
	PositionEntity b,X,Y,Z
	AlignToVector b,NX,NY,NZ,3,1
	MoveEntity b,0,0,.025
	
	CreateParticle(s)
	CreateParticle(e)
	CreateParticle(b)
End Function

Function CreateTorch()
	Tiles = FXP_SetupTilesets()
	
	E = CreateEmitter()
	ApplyTexture E,Tiles,0
	SetEmitterTranslation E,0,.045,0
	SetEmitterLifespan E,600,400
	SetEmitterBlend E,3
	SetEmitterSizeFrom E,.45,.45
	SetEmitterColor E,209,151,78,1
	SetEmitterColorTo E,150,80,0,0
	SetEmitterColorJitter E,42,42,42,0,1
	SetEmitterSizeTo E,1.25,1.25
	SetEmitterRandomRotation E,0,0,50
	SetEmitterViewMode E,1
	SetEmitterSizeJitter E,.25,.25,.25,1,1,0
	
	N = CreateEmitter()
	ApplyTexture N,Tiles,7
	SetEmitterParent N,E
	SetEmitterChildMode E,2
	SetEmitterTranslation N,0,.045,0
	SetEmitterVelocity N,0,0,.0025
	SetEmitterRandomRotation N,20,360,180
	SetEmitterLifeSpan N,3500
	SetEmitterColorFrom N,120,120,120,.7
	SetEmitterColorTo N,100,100,100,0
	SetEmitterBlend N,1
	SetEmitterWaitSpan E,2
	SetEmitterWaitSpan N,5
	SetEmitterSizeJitter N,.5,.5,.5,1,1,0
	SetEmitterLifeMode N,2
	SetEmitterSizeFrom N,.05,.05
	SetEmitterSizeTo N,1.5,1.5
	SetEmitterEmissionRate E,1
	SetEmitterLifeMode E,2
	
	SetEmitterCulling N,0
	
	Return E
End Function

;#Region LotusXML.bb
	;#Region DESCRIPTION
		; XML load / parse / save functions
		; Written by Blitztastic, butchered by Noel Cower
	;#End Region
	
	;#Region CLASSES
		Type XMLnodelist
			Field node.XMLnode
			Field nextnode.XMLnodelist
			Field prevnode.XMLnodelist
		End Type
		
		; for internal use, do not use in code outside of this file
		Type XMLworklist
			Field node.XMLnode
		End Type
		
		
		Type XMLnode
			Field tag$,value$,path$
			Field firstattr.XMLattr
			Field lastattr.XMLattr	
			Field attrcount,fileid
			Field endtag$
			
			; linkage functionality
			Field firstchild.XMLnode
			Field lastchild.XMLnode
			Field childcount
			Field nextnode.XMLnode
			Field prevnode.XMLnode
			Field parent.XMLnode
		End Type
		
		Type XMLattr
			Field name$,value$
			Field sibattr.XMLattr
			Field parent.XMLnode
		End Type
		
		Global XMLFILEID
	;#End Region
	
	;#Region PROCEDURES
		Function ReadXML.XMLnode(filename$)
			infile = ReadFile(filename$)
			XMLFILEID=MilliSecs()
			x.XMLnode = XMLReadNode(infile,Null)
			CloseFile infile
			Return x
		End Function
		
		Function WriteXML(filename$,node.XMLnode,writeroot=False)
			outfile = WriteFile(filename$)
			WriteLine outfile,"<?xml version="+Chr$(34)+"1.0"+Chr$(34)+" ?>"
			XMLwriteNode(outfile,node)
			CloseFile outfile
		End Function
		
		Function XMLOpenNode.XMLnode(parent.XMLnode,tag$="")
			x.XMLnode = New XMLnode
			x	ag$=tag$
			xfileid = XMLFILEID; global indicator to group type entries (allows multiple XML files to be used)
			XMLaddNode(parent,x)
			Return x
		End Function
		
		Function XMLCloseNode.XMLnode(node.XMLnode)
			Return nodeparent
		End Function
		
		; adds node to end of list (need separate function for insert, or mod this on)
		Function XMLAddNode(parent.XMLnode,node.XMLnode)
			If parent <> Null
				If parentchildcount = 0 Then
					parentfirstchild = node
				Else
					parentlastchild
extnode = node
				End If
				nodeprevnode = parentlastchild
				parentlastchild = node
				parentchildcount = parentchildcount +1
				nodepath$ = parentpath$+parent	ag$
			End If
			nodeparent = parent
			nodepath$=nodepath$+"/"
		End Function
		
		Function XMLDeleteNode(node.XMLnode)
			n.XMLnode = nodefirstchild
			; delete any children recursively
			While n <> Null
				nn.XMLnode= n
extnode
				XMLdeletenode(n)
				n = nn
			Wend
		
			; delete attributes for this node
			a.XMLattr = nodefirstattr
			While a <> Null
				na.XMLattr = asibattr
				Delete a
				a = na
			Wend
		
			; dec parents child count
			If nodeparent <> Null
				nodeparentchildcount = nodeparentchildcount -1
				
				; heal linkages
				If nodeprevnode <> Null Then nodeprevnode
extnode = node
extnode
				If node
extnode <> Null Then node
extnodeprevnode = nodeprevnode
				If nodeparentfirstchild = node Then nodeparentfirstchild = node
extnode
				If nodeparentlastchild = node Then nodeparentlastchild = nodeprevnode
			End If
			; delete this node		
			Delete node
		
		End Function
		
		; node functions
		Function XMLfindNode.XMLnode(node.XMLnode,path$)
		
			ret.XMLnode = Null
			p=Instr(path$,"/")
			If p > 0 Then 
				tag$=Left$(path$,p-1)
				a.XMLnode = node
				While ret=Null And a<>Null 
					If Lower(tag$)=Lower(a	ag$) Then
						If p=Len(path$) Then
								ret = a
						Else
							If afirstchild <> Null Then
								ret = XMLfindnode(afirstchild,Mid$(path$,p+1))
							End If
						End If
					End If
					a = a
extnode
				Wend
			End If
			Return ret
		End Function
		
		Function XMLDeleteList(nl.XMLnodelist)
			While nl <> Null
				na.XMLnodelist = nl
extnode
				Delete nl
				nl = na
			Wend
		End Function
		
		
		Function XMLSelectNodes.XMLnodelist(node.XMLnode,path$,recurse=True)
			root.XMLnodelist=Null
			XMLselectnodesi(node,path$,recurse)
			prev.XMLnodelist=Null
			c = 0
			For wl.XMLworklist = Each XMLworklist
				c = c + 1
				nl.XMLnodelist = New XMLnodelist
				nl
ode = wl
ode
				If prev = Null Then 
					root = nl
					prev = nl
				Else
					prev
extnode = nl
					nlprevnode = prev
				End If
				prev = nl
				Delete wl
			Next
			;gak debuglog "XML: "+c+" nodes selected"
			Return root
		End Function
		
		; internal selection function, do not use outside this file
		Function XMLSelectNodesI(node.XMLnode,path$,recurse=True)
			wl.XMLworklist=Null
			If node = Null Then
			End If
			ret.XMLnode = Null
			p=Instr(path$,"/")
			If p > 0 Then 
				tag$=Left$(path$,p-1)
				a.XMLnode = node
				While a<>Null 
					If Lower(path$)=Lower(Right$(apath$+a	ag$+"/",Len(path$))) Then
							wl = New XMLworklist
							wl
ode = a
					End If
					If afirstchild <> Null And (recurse) Then
						XMLSelectNodesI(afirstchild,path$)
					End If
					a = a
extnode
				Wend
			End If
		
		End Function
		
		Function XMLNextNode.XMLnode(node.XMLnode)
			Return node
extnode
		End Function
		
		Function XMLPrevNode.XMLnode(node.XMLnode)
			Return nodeprevnode
		End Function
		
		Function XMLAddAttr(node.XMLnode,name$,value$)
			;gak debuglog "XML:adding attribute "+name$+"="+value$+" ("+Len(value$)+")"
			a.XMLattr = New XMLattr
			a
ame$ = name$
			avalue$ = value$
			If nodeattrcount = 0 Then
				nodefirstattr = a
			Else
				nodelastattrsibattr = a
			End If
			nodelastattr=a
			nodeattrcount = nodeattrcount + 1
			aparent = node
			If Upper(avalue)="TRUE" avalue=1
			If Upper(aValue)="FALSE" avalue=0
			If Upper(aValue)="GRAPHICSWIDTH" avalue=GraphicsWidth()
			If Upper(aValue)="GRAPHICSHEIGHT" avalue=GraphicsHeight()
		End Function
		
		Function XMLReadNode.XMLnode(infile,parent.XMLnode,pushed=False)
			mode = 0
			root.XMLnode = Null
			cnode.XMLnode = Null
			x.XMLnode = Null
			ispushed = False
			done = False
			While (Not done) And (Not Eof(infile))
				c = ReadByte(infile)
				If c<32 Then c=32
				ch$=Chr$(c)
		;		;gak debuglog "{"+ch$+"} "+c+" mode="+mode
				Select mode
				  Case 0 ; looking for the start of a tag, ignore everything else
					If ch$ = "<" Then 
						mode = 1; start collecting the tag
					End If
				  Case 1 ; check first byte of tag, ? special tag
					If ch$ = "?" Or ch$ = "!" Then
				 		mode = 0; class special nodes as garbage & consume
					Else
						If ch$ = "/" Then 
							mode = 2 ; move to collecting end tag
							xendtag$=ch$
							;gak debuglog "** found end tag"
						Else
							cnode=x
							x.XMLnode = XMLOpennode(cnode)
							If cnode=Null Then root=x
							x	ag$=ch$
							mode = 3 ; move to collecting start tag
						End If
					End If
				  Case 2 ; collect the tag name (close tag)
					If ch$=">" Then 
						mode = 0 ; end of the close tag so jump out of loop
						;done = True
						x = XMLclosenode(x)
					Else 
						xendtag$ = xendtag$ + ch$
					End If
				  Case 3 ; collect the tag name 
					If ch$=" " Then 
						;gak debuglog "TAG:"+x	ag$
						mode = 4 ; tag name collected, move to collecting attributes
					Else 
						If ch$="/" Then 
							;gak debuglog "TAG:"+x	ag$
							xendtag$=x	ag$
							mode = 2; start/end tag combined, move to close
						Else
							If ch$=">" Then
								;gak debuglog "TAG:"+x	ag$
								mode = 20; tag closed, move to collecting value
							Else
								x	ag$ = x	ag$ + ch$
							End If
						End If
					End If
				  Case 4 ; start to collect attributes
					If Lower(ch$)>="a" And Lower(ch$)<="z" Then 
						aname$=ch$;
						mode = 5; move to collect attribute name
					Else
						If ch$=">" Then
							xvalue$=""
							mode = 20; tag closed, move to collecting value
						Else
							If ch$="/" Then 
								mode = 2 ; move to collecting end tag
								xendtag$=ch$
								;gak debuglog "** found end tag"
							End If
						End If
					End If
				  Case 5 ; collect attribute name
					If ch$="=" Then
					  ;gak debuglog "ATT:"+aname$
					  aval$=""
					  mode = 6; move to collect attribute value
					Else
					  aname$=aname$+ch$
					End If
				  Case 6 ; collect attribute value
					If c=34 Then
						mode = 7; move to collect string value
					Else
						If c <= 32 Then 
							;gak debuglog "ATV:"+aname$+"="+aval$
							XMLAddAttr(x,aname$,aval$)
							mode = 4; start collecting a new attribute
						Else
					   		aval$=aval$+ch$
						End If
					End If
				  Case 7 ; collect string value
					If c=34 Then
						;gak debuglog "ATV:"+aname$+"="+aval$
						XMLADDattr(x,aname$,aval$)
						mode = 4; go and collect next attribute
					Else
						aval$=aval$+ch$
					End If
				  Case 20 ; COLLECT THE VALUE PORTION
					If ch$="<" Then 
						;gak debuglog "VAL:"+x	ag$+"="+xvalue$
						mode=1; go to tag checking
					Else
						xvalue$=xvalue$+ch$
					End If
				End Select
				
				If Eof(infile) Then done=True
			
			Wend
		
			Return root
		
		End Function
		
		; write out an XML node (and children)
		Function XMLWriteNode(outfile,node.XMLnode,tab$="")
		;	;gak debuglog "Writing...."+node	ag$+".."
			s$="<"+node	ag$
			a.XMLattr = nodefirstattr
			While a<>Null
				s$ = s$+" "+Lower(a
ame$)+"="+Chr$(34)+avalue$+Chr$(34)
				a = asibattr
			Wend
			
			If nodevalue$="" And nodechildcount = 0 Then
				s$=s$+"/>"
				et$=""
			Else
				s$=s$+">"+nodevalue$
				et$="</"+node	ag$+">"
			End If
			
			WriteLine outfile,XMLcleanStr$(tab$+s$)
			n.XMLnode = nodefirstchild
			While n <> Null
				XMLwriteNode(outfile,n,tab$+"  ")
				n = n
extnode
			Wend
			
			If et$<> "" Then WriteLine outfile,XMLCleanStr$(tab$+et$)
		
		End Function
		
		; remove non-visible chars from the output stream
		Function XMLCleanStr$(s$)
			a$=""
			For i = 1 To Len(s$)
				If Asc(Mid$(s$,i,1))>=32 Then a$ = a$ +Mid$(s$,i,1)
			Next
			Return a$
		
		End Function
		
		; attribute functions
		; return an attribute of a given name
		Function XMLFindAttr.XMLattr(node.XMLnode,name$)
			ret.XMLattr = Null
			If node <> Null Then 
				a.XMLattr = nodefirstattr
				done = False
				While ret=Null And a<>Null 
					If Lower(name$)=Lower(a
ame$) Then
						ret = a
					End If
					a = asibattr
				Wend
			End If
			Return ret
		End Function
		
		; return an attribute value as a string
		Function XMLAttrValueStr$(node.XMLnode,name$,dflt$="")
			ret$=dflt$
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret$=avalue$
			Return ret$
		End Function
		
		; return an attribute value as an integer
		Function XMLAttrValueInt(node.XMLnode,name$,dflt=0)
			ret=dflt
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret=avalue
			Return ret
		End Function
		
		; return an attribute value as a float
		Function XMLAttrValueFloat#(node.XMLnode,name$,dflt#=0)
			ret#=dflt#
			a.XMLattr = XMLfindattr(node,name$)
			If a <> Null Then ret#=avalue
			Return ret
		End Function
		
		Function XMLHasChildren(node.XMLnode)
			Return nodefirstchild <> Null
		End Function
		
		Function XMLHasAttributes(node.XMLnode)
			Return nodefirstattr <> Null
		End Function
		
		Function XMLGetChild.XMLNode(node.XMLNode,index=0)
			child.XMLNode = nodeFirstChild
			For i = 0 To index-1
				child.XMLNode = child
extnode
			Next
			Return child
		End Function
		
		Function XMLGetFirstAttribute.XMLAttr(node.XMLNode)
			Return nodefirstattr
		End Function
		
		Function XMLGetNextAttribute.XMLAttr(attr.XMLAttr)
			Return attrsibattr
		End Function
		
		Function XMLHasAttribute(n.XMLNode,attr$)
			If XMLHasAttributes(n) = 0 Then Return 0
			
			a.XMLAttr = XMLGetFirstAttribute(n)
			While (a <> Null)
				If Lower(a
ame) = Lower(attr) Return 1
				a = XMLGetNextAttribute(a)
			Wend
			Return 0
		End Function
		
		Function XMLGetParent.XMLNode(node.XMLNode)
			Return nodeparent
		End Function
		
		Function PrintXMLNode(i.XMLNode,start$="")
			If i = Null Then Return
			Write start+"<"+i	ag
			a.XMLAttr = XMLGetFirstAttribute(i)
			While a <> Null
				Write " "+a
ame+"="+Chr(34)+avalue+Chr(34)
				a = XMLGetNextAttribute(a)
			Wend
			Write ">"
			Print ""
			
			f.XMLNode = XMLGetChild(i,0)
			While f.XMLNode <> Null
				PrintXMLNode(f,start+"    ")
				f = XMLNextNode(f)
			Wend
			Print start+"</"+i	ag+">"
		End Function
	;#End Region
;#End Region

;; DE/INITIALIZATION
Function InitLotus()
	Dim gSine#(359)
	Dim gCosine#(359)
	
	For A = 0 To 359
		gSine#(A) = Sin(A)
		gCosine#(A) = Cos(A)
	Next
	
	gLotusParticlePivot = CreatePivot()
	gLotusTPivot = CreatePivot()
	gLotusParticleMesh = CreateMesh()
	EntityFX gLotusParticleMesh,1+2+8+16+32
	
	gLotusNullTexture.LotusTexture = New LotusTexture
	gNullTexture = Handle(gLotusNullTexture)
	gLotusNullTextureRows = 1
	gLotusNullTextureColumns = 1
	gLotusNullTextureUStep = 1
	gLotusNullTextureVStep = 1
	
	Brush = CreateBrush()
	BrushFX Brush,1+2+16+32
	
	BrushBlend Brush,1
	gLotusNullTextureAlpha = CreateSurface(gLotusParticleMesh)
	PaintSurface gLotusNullTextureAlpha,Brush
	
	FreeBrush Brush
	
	gNullLotusVector = New LotusVector
	gTempLotusVector = New LotusVector
	
	If cUSE_EMITTERCONES Then
		gLotusEmitterTexture = CreateTexture(64,64,1+16+32)
		Buffer = GraphicsBuffer()
		T = gLotusEmitterTexture
		SetBuffer TextureBuffer(T)
		R = ColorRed()
		G = ColorGreen()
		B = ColorBlue()
		Color 255,255,255
		Rect 0,0,64,64,True
		Color 255,120,40
		Rect 0,60,64,4
		Color R,G,B
		SetBuffer Buffer
	EndIf
	
	gLotusParticleCount = 0
	
	gWidth = GraphicsWidth()
	gHeight = GraphicsHeight()
End Function

Function KillLotus()
	Dim gSine#(0)
	Dim gCosine#(0)
	FreeEntity gLotusParticlePivot
	FreeEntity gLotusTPivot
	FreeEntity gLotusParticleMesh
	If cUSE_EMITTERCONES Then FreeTexture gLotusEmitterTexture
	gLotusParticlePivot = 0
	gLotusParticleMesh = 0
	gLotusEmitterTexture = 0
	
	For T.LotusTexture = Each LotusTexture
		FreeTexture TBitmap
	Next
	
	For E.LotusEmitter = Each LotusEmitter
		FreeEntity EEntity
	Next
	
	For G.LotusGraph = Each LotusGraph
		FreeBank GBank
	Next
	
	For D.LotusDeflector = Each LotusDeflector
		FreeEntity DEntity
	Next
	
	Delete Each LotusParticle
	Delete Each LotusEmitter
	Delete Each LotusGraph
	Delete Each LotusDeflector
	Delete Each LotusVector
	Delete Each LotusTexture
	Delete Each LotusStringPiece
	gLotusParticleCount = 0
End Function


;; TEXTURE
Function LoadLotusTexture(Path$,Flags%=59,Alpha=0,Multiply=0,Add=0)
	For T.LotusTexture = Each LotusTexture
		If Lower(TPath) = Lower(Path) Then Return Handle(T)
	Next
	Bitmap = LoadTexture(Path$,Flags)
	If Bitmap = 0 Then Return False
	T.LotusTexture = New LotusTexture
	TBitmap = Bitmap
	TFlags = Flags
	TRows = 1
	TColumns = 1
	TUStep = 1
	TVStep = 1
	TPath = Path
	SetTextureBlendModes Handle(T),Alpha,Multiply,Add
	Return Handle(T)
End Function

Function LoadLotusAnimTexture(Path$,Flags%=59,Rows%=1,Columns%=1,Alpha=0,Multiply=0,Add=0)
	For T.LotusTexture = Each LotusTexture
		If Lower(TPath) = Lower(Path) Then Return Handle(T)
	Next
	Texture = LoadLotusTexture(Path$,Flags,Alpha,Multiply,Add)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Or T = gLotusNullTexture Then Return False
	Rows = Min(Rows,1):Columns = Min(Columns,1)
	TRows = Rows
	TColumns = Columns
	FrameWidth# = TextureWidth(TBitmap)/Columns
	FrameHeight# = TextureHeight(TBitmap)/Rows
	TUStep = FrameWidth/TextureWidth(TBitmap)
	TVStep = FrameHeight/TextureHeight(TBitmap)
	Return Texture
End Function

Function LoadLotusTileSet(Path$,Flags%=59,Rows%=3,Columns%=3,Alpha=0,Multiply=0,Add=0)
	For T.LotusTexture = Each LotusTexture
		If Lower(TPath) = Lower(Path) Then Return Handle(T)
	Next
	Texture = LoadLotusTexture(Path$,Flags,Alpha,Multiply,Add)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Or T = gLotusNullTexture Then Return False
	Rows = Min(Rows,1):Columns = Min(Columns,1)
	TRows = Rows
	TColumns = Columns
	FrameWidth# = TextureWidth(TBitmap)/Columns
	FrameHeight# = TextureHeight(TBitmap)/Rows
	TUStep = FrameWidth/TextureWidth(TBitmap)
	TVStep = FrameHeight/TextureHeight(TBitmap)
	Return Texture
End Function

Function ApplyTexture(Emitter,Texture,Frame=-1,Animated%=-1,FrameLength%=-1)
	If EmitterExists( Emitter ) = 0 Then Return False
	E.LotusEmitter = Object.LotusEmitter(Int(EntityName(Emitter)))
	If E = Null Then Return False
	ETexture = Object.LotusTexture(Texture)
	If Frame > -1 Then EFrame = Frame EFrameStart = Frame
	If Animated > -1 Then EAnimated = Animated
	If FrameLength > -1 Then EFrameLength = FrameLength
End Function

Function SetTextureTiles(Texture,Rows,Columns)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Or T = gLotusNullTexture Then Return False
	Rows = Min(Rows,1):Columns = Min(Columns,1)
	TRows = Rows
	TColumns = Columns
	FrameWidth# = TextureWidth(TBitmap)/Columns
	FrameHeight# = TextureHeight(TBitmap)/Rows
	TUStep = FrameWidth/TextureWidth(TBitmap)
	TVStep = FrameHeight/TextureHeight(TBitmap)
	Return True
End Function

Function SetTextureBlendModes(Texture,Alpha=True,Multiply=False,Add=True,RebuildSurfaces = 0)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Then Return False
	Brush = CreateBrush()
	BrushTexture Brush,TBitmap
	BrushFX Brush,1+2+16+32
	
	If Add > 0 And (TAdd = 0 Or RebuildSurfaces > 0)
		TAdd = CreateSurface(gLotusParticleMesh)
		BrushBlend Brush,3
		PaintSurface TAdd,Brush
	ElseIf Add = 0 And TAdd <> 0 Then
		TAdd = 0
		Rebuild = True
	EndIf
	
	If Alpha > 0 And (TAlpha = 0 Or RebuildSurfaces > 0)
		TAlpha = CreateSurface(gLotusParticleMesh)
		BrushBlend Brush,1
		PaintSurface TAlpha,Brush
	ElseIf Alpha = 0 And TAlpha <> 0 Then
		TAlpha = 0
		Rebuild = True
	EndIf
	
	If Multiply > 0 And (TMultiply = 0 Or RebuildSurfaces > 0)
		TMultiply = CreateSurface(gLotusParticleMesh)
		BrushBlend Brush,2
		PaintSurface TMultiply,Brush
	ElseIf Multiply = 0 And TMultiply <> 0 Then
		TMultiply = 0
		Rebuild = True
	EndIf
	
	If Rebuild Then RebuildLotusTextures()
	
	FreeBrush Brush
End Function

Function FreeLotusTexture(Texture)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Then Return False
	FreeTexture TBitmap
	Delete T
	RebuildLotusTextures()
End Function

Function ClearLotusTextures()
	For T.LotusTexture = Each LotusTexture
		If T <> gLotusNullTexture Then
			FreeTexture TBitmap
			Delete T
		EndIf
	Next
	
	RebuildLotusTextures()
End Function

Function RebuildLotusTextures()
	FreeEntity gLotusParticleMesh
	gLotusParticleMesh = CreateMesh()
	EntityFX gLotusParticleMesh,1+2+16+32
	
	Brush = CreateBrush()
	BrushFX Brush,1+2+16+32
	
	BrushBlend Brush,1
	gLotusNullTextureAlpha = CreateSurface(gLotusParticleMesh)
	PaintSurface gLotusNullTextureAlpha,Brush
	
	FreeBrush Brush
	
	For T.LotusTexture = Each LotusTexture
		If T <> gLotusNullTexture Then SetTextureBlendModes Handle(T),Abs(TAlpha),Abs(TMultiply),Abs(TAdd),1
	Next
End Function

Function TextureUsesAdd(Texture)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Then Return False
	If T = gLotusNullTexture Then Return True
	If TAdd <> 0 Then Return True
End Function

Function TextureUsesMultiply(Texture)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Then Return False
	If T = gLotusNullTexture Then Return True
	If TAlpha <> 0 Then Return True
End Function

Function TextureUsesAlpha(Texture)
	T.LotusTexture = Object.LotusTexture(Texture)
	If T = Null Then Return False
	If T = gLotusNullTexture Then Return True
	If TAlpha <> 0 Then Return True
End Function
	
;; DEFLECTOR
Function DeflectorExists(Deflector)
	For D.LotusDeflector = Each LotusDeflector
		If DEntity = Deflector Then
			Return DEntity
		EndIf
	Next
	Return 0
End Function

Function CreateDeflector(Parent=0)
	D.LotusDeflector = New LotusDeflector
	DRadius = 0
	DStrength = .5
	DActive = 0
	DEntity = CreatePivot()
	NameEntity DEntity,Handle(D)
	Return DEntity
End Function

Function SetDeflectorStrength(Deflector, Strength#=.5)
	If DeflectorExists(Deflector) = 0 Then Return False
	D.LotusDeflector = Object.LotusDeflector(EntityName(Deflector))
	If D = Null Then Return False
	DStrength = Strength
End Function

Function SetDeflectorActive(Deflector,Active = 1)
	If DeflectorExists(Deflector) = 0 Then Return False
	D.LotusDeflector = Object.LotusDeflector(EntityName(Deflector))
	If D = Null Then Return False
	DActive = Active
End Function

Function SetDeflectorRadius(Deflector, Radius#=0)
	If DeflectorExists(Deflector) = 0 Then Return False
	D.LotusDeflector = Object.LotusDeflector(EntityName(Deflector))
	If D = Null Then Return False
	DRadius = Radius
End Function

Function ActivateDeflector(Deflector)
	If DeflectorExists(Deflector) = 0 Then Return False
	D.LotusDeflector = Object.LotusDeflector(EntityName(Deflector))
	If D = Null Then Return False
	DActive = True
End Function

Function DeActivateDeflector(Deflector)
	If DeflectorExists(Deflector) = 0 Then Return False
	D.LotusDeflector = Object.LotusDeflector(EntityName(Deflector))
	If D = Null Then Return False
	DActive = False
End Function
	


;; EMITTER
Function NameEmitter(Emitter,Name$)
	If EmitterExists( Emitter ) = 0 Then Return False
	E.LotusEmitter = Object.LotusEmitter(Int(EntityName(Emitter)))
	If E = Null Then Return False
	EName = Name$
End Function

Function GetEmitterName$(Emitter)
	If EmitterExists( Emitter ) = 0 Then Return False
	E.LotusEmitter = Object.LotusEmitter(Int(EntityName(Emitter)))
	If E = Null Then Return False
	Return EName
End Function

Function CreateEmitter%(Texture = 0)
	If Texture = 0 Then Texture = Handle(gLotusNullTexture)
	If cUSE_EMITTERCONES Then 
		P = CreateCone(4)
		For S = 1 To CountSurfaces(P)
			Surface = GetSurface(P,S)
			For V = 0 To CountVertices(Surface)-1
				eV# = 1.0-VertexY(Surface,V)/2
				eU# = VertexX(Surface,V)/2
				If eV > 1 Then eV = eV - .5
				If eV < 0 Then eV = eV + .5
				If eV > 1 Then Stop
				VertexTexCoords Surface,V,eU,eV,0,0
			Next
		Next
		Surface = 0
		EntityTexture P,gLotusEmitterTexture
		EntityFX P,1
		RotateMesh P,-90,0,0
		PositionMesh P,0,0,-2
	Else
		P = CreatePivot()
	EndIf
	
	HideEntity P
	E.LotusEmitter = New LotusEmitter
	NameEntity P,Handle(E)
	
	EWeight = 1
	ETexture = Object.LotusTexture(Texture)
	EEntity = P
	EWaitSpan = 1
	EDWaitSpan = 1
	ECircleSpeedX = 1
	ECircleSpeedY = 1
	ECircleSpeedZ = 1
	ESizeFromX = 1
	ESizeFromY = 1
	ESizeFromZ = 1
	ESizeToX = 1
	ESizeToY = 1
	ESizeToZ = 1
	EWaveSpeedX = 1
	EWaveSpeedY = 1
	EWaveSpeedZ = 1
	ERedFrom = 255
	EBlueFrom = 255
	EGreenFrom = 255
	ERedTo = 255
	EBlueTo = 255
	EGreenTo = 255
	EAlphaFrom = 1.0
	EBlendMode = 1
	ELifeSpan = 80
	EEmissionRate = 1
	ECull = 1
	ESorting = 1
	EViewMode = 1
	ELifeMode = 1
	EChildMode = 1
	EActiveSpan = -1
	EActive = -1
	Return P
End Function

Function LoadEmitter%(Path$,Flags%=59,Alpha=1,Multiply=0,Add=0)
	For T.LotusTexture = Each LotusTexture
		If Lower(TPath$) = Lower(Path$) Then Exit
	Next
	If T <> Null Then
		Return CreateEmitter(Handle(T))
	EndIf
	
	Texture = LoadLotusTexture(Path$,Flags,Alpha,Multiply,Add)
	Return CreateEmitter(Texture)
End Function

Function KillLotusEmitter(Emitter)	;; Recommendation: When calling this or FreeEmitter(E), call it like so: YourEmitter = FreeEmitter(YourEmitter) so that the integer, YourEmitter, gets set to zero
	If EmitterExists( Emitter ) = 0 Then Return False
	E.LotusEmitter = Object.LotusEmitter(Int(EntityName(Emitter)))
	If E = Null Then Return False
		
	If EEmitSoundChannel Then StopChannel( EEmitSoundChannel )
	Delete E
	FreeEntity Emitter
	Return 0
End Function

Function FreeEmitter(Emitter)
	Return KillLotusEmitter( Emitter )
End Function

Function ClearEmitters()		;; Reset all references to emitters to 0 after calling this
	For E.LotusEmitter = Each LotusEmitter
		KillLotusEmitter EEntity
	Next
End Function

Function EmitterExists(Emitter)
	For E.LotusEmitter = Each LotusEmitter
		If EEntity = Emitter Then Return EEntity
	Next
	Return 0
End Function

Function CopyEmitter(Emitter)
	If EmitterExists( Emitter ) = 0 Then Return False
	EOld.LotusEmitter = Object.LotusEmitteR(Int(EntityName$(Emitter)))
	If EOld = Null Then Return False
	If cUSE_EMITTERCONES Then
		P = CreateCone(4)
		For S = 1 To CountSurfaces(P)
			Surface = GetSurface(P,S)
			For V = 0 To CountVertices(Surface)-1
				eV# = 1.0-VertexY(Surface,V)/2
				eU# = VertexX(Surface,V)/2
				If eV > 1 Then eV = eV - .5
				If eV < 0 Then eV = eV + .5
				If eV > 1 Then Stop
				VertexTexCoords Surface,V,eU,eV,0,0
			Next
		Next
		Surface = 0
		EntityTexture P,gLotusEmitterTexture
		EntityFX P,1
		RotateMesh P,-90,0,0
		PositionMesh P,0,0,-2
	Else
		P = CreatePivot()
	EndIf
	HideEntity P
	E.LotusEmitter = New LotusEmitter
	NameEntity P,Handle(E)
	PositionEntity P,EntityX(Emitter,True),EntityY(Emitter,True),EntityZ(Emitter,True)
	RotateEntity P,EntityPitch(Emitter,True),EntityYaw(Emitter,True),EntityRoll(Emitter,True)
	ETexture = EOldTexture
	EFrame = EOldFrame
	EAnimated = EOldAnimated
	EEntity = P
	ETranslationJitterX = EOldTranslationJitterX
	ETranslationJitterY = EOldTranslationJitterY
	ETranslationJitterZ = EOldTranslationJitterZ
	ETranslationX = EOldTranslationX
	ETranslationY = EOldTranslationY
	ETranslationZ = EOldTranslationZ
	EVelocityX = EOldVelocityX
	EVelocityY = EOldVelocityY
	EVelocityZ = EOldVelocityZ
	EAngleVelocityX = EOldAngleVelocityX
	EAngleVelocityY = EOldAngleVelocityY
	EAngleVelocityZ = EOldAngleVelocityZ
	EAccelerationX = EOldAccelerationX
	EAccelerationY = EOldAccelerationY
	EAccelerationZ = EOldAccelerationZ
	EAngleAccelerationX = EOldAngleAccelerationX
	EAngleAccelerationY = EOldAngleAccelerationY
	EAngleAccelerationZ = EOldAngleAccelerationZ
	ESizeFromX = EOldSizeFromX
	ESizeFromY = EOldSizeFromY
	ESizeFromZ = EOldSizeFromZ
	ESizeToX = EOldSizeToX
	ESizeToY = EOldSizeToY
	ESizeToZ = EOldSizeToZ
	ESizeJitterX = EOldSizeJitterX
	ESizeJitterY = EOldSizeJitterY
	ESizeJitterZ = EOldSizeJitterZ
	EVelocityJitterX = EOldVelocityJitterX
	EVelocityJitterY = EOldVelocityJitterY
	EVelocityJitterZ = EOldVelocityJitterZ
	ECubeX = EOldCubeX
	ECubeY = EOldCubeY
	ECubeZ = EOldCubeZ
	ECylinderX = EOldCylinderX
	ECylinderY = EOldCylinderY
	ECylinderZ = EOldCylinderZ
	EWaveRadiusX = EOldWaveRadiusX
	EWaveRadiusY = EOldWaveRadiusY
	EWaveRadiusZ = EOldWaveRadiusZ
	EWaveSpeedX = EOldWaveSpeedX
	EWaveSpeedY = EOldWaveSpeedY
	EWaveSpeedZ = EOldWaveSpeedZ
	ECircleSpeedX = EOldCircleSpeedX
	ECircleSpeedY = EOldCircleSpeedY
	ECircleSpeedZ = EOldCircleSpeedZ
	ECircleRadiusX = EOldCircleRadiusX
	ECircleRadiusY = EOldCircleRadiusY
	ECircleRadiusZ = EOldCircleRadiusZ
	ERandomRotationX = EOldRandomRotationX
	ERandomRotationY = EOldRandomRotationY
	ERandomRotationZ = EOldRandomRotationZ
	ETranslationJitterUp = EOldTranslationJitterUp
	ETranslationJitterDown = EOldTranslationJitterDown
	EVelocityJitterUp = EOldVelocityJitterUp
	EVelocityJitterDown = EOldVelocityJitterDown
	ERedFrom = EOldRedFrom
	EGreenFrom = EOldGreenFrom
	EBlueFrom = EOldBlueFrom
	EAlphaFrom = EOldAlphaFrom
	ERedTo = EOldRedTo
	EGreenTo = EOldGreenTo
	EBlueTo = EOldBlueTo
	EAlphaTo = EOldAlphaTo
	EBlendMode = EOldBlendMode
	ELifeSpan = EOldLifeSpan
	EWaitSpan = EOldWaitSpan
	EDWaitSpan = EOldDWaitSpan
	EWaitSpanJitter = EOldWaitSpanJitter
	EParticleMesh = EOldParticleMesh
	EEmit = EOldEmit
	ESizeJitterUniform = EOldSizeJitterUniform
	EColorJitterRed = EOldColorJitterRed
	EColorJitterGreen = EOldColorJitterGreen
	EColorJitterBlue = EOldColorJitterBlue
	EColorJitterAlpha = EOldColorJitterAlpha
	EColorJitterUniform = EOldColorJitterUniform
	EColorJitterDown = EOldColorJitterDown
	EColorJitterUp = EOldColorJitterUp
	EFrozen = EOldFrozen
	EHidden = EOldHidden
	EEmissionRate = EOldEmissionRate
	EViewMode = EOldViewMode
	ELifeMode = EOldLifeMode
	EChildMode = EOldChildMode
	EGravity = EOldGravity
	EGravityEnabled = EOldGravityEnabled
	EWeight = EOldWeight
	ESizeJitterUp = EOldSizeJitterUp
	ESizeJitterDown = EOldSizeJitterDown
	ECull = EOldCull
	ESorting = EOldSorting
	ERollMode = EOldRollMode
	ERange = EOldRange
	ELifeSpanJitter = EOldLifeSpanJitter
	ELifeSpanJitterUp = EOldLifeSpanJitterUp
	ELifeSpanJitterDown = EOldLifeSpanJitterDown
	EColorGraph = EOldColorGraph
	ESizeGraph = EOldSizeGraph
	EEmitSound = EOldEmitSound
	EBounceSound = EOldBounceSound
	ELoopEmitSound = EOldLoopEmitSound
	EVelocityDecay = EOldVelocityDecay
	ESplineMesh = EOldSplineMesh
	EActiveSpan = EOldActiveSpan
	EActive = EOldActive
	EFreeOnEndActive = EOldFreeOnEndActive
	EDeflectorsAffect = EOldDeflectorsAffect
	EParent = EOldParent
	EChild = EOldChild
	ETrail = EOldTrail
	EntityParent EEntity,GetParent(EOldEntity)
	Return P
End Function

Function SortParticles()
	Dim gAlphaPartArray#( Min(gLotusAlphaParticleCount-1,0), 1 )
	For P.LotusParticle = Each LotusParticle
		If PBlendMode = 1 And PSorting >= 1 Then
			PositionEntity gLotusParticlePivot, PPositionX, PPositionY, PPositionZ, 1
			gAlphaPartArray( ACount, 0 ) = -EntityDistance( gLotusCamera, gLotusParticlePivot )
			gAlphaPartArray( ACount, 1 ) = Handle( P )
			ACount = ACount + 1
		EndIf
		If ACount >= gLotusAlphaParticleCount Then Exit
	Next
	
	If gLotusAlphaParticleCount > 1 Then
		lSort( 0, gLotusAlphaParticleCount-1 )
	EndIf
End Function

;; UPDATE
Function UpdateLotusParticles(DeltaTime#=1,Camera=0)

	gLotusParticlesDrawn = 0
	Local ET% = MilliSecs()
;	gLotusUpdateTimes( uptTimeAll ) = ET
	
;	gLotusUpdateTimes( updTimeTexture ) = MilliSecs()
	For T.LotusTexture = Each LotusTexture
		If TAdd <> 0 Then ClearSurface TAdd,1,1
		If TMultiply <> 0 Then ClearSurface TMultiply,1,1
		If TAlpha <> 0 Then ClearSurface TAlpha,1,1
	Next
;	gLotusUpdateTimes( updTimeTexture ) = MilliSecs() - gLotusUpdateTimes( updTimeTexture )
	
	If Camera = 0 Then
		Camera = gLotusCamera
		If Camera = 0 Then Return False
	Else
		gLotusCamera = Camera
	EndIf
	
	If DeltaTime > 0 Then
	;	gLotusUpdateTimes( updTimeEmit ) = MilliSecs()
		For E.LotusEmitter = Each LotusEmitter
			KillIt = False
			
			EPositionX = EntityX(EEntity,1)
			EPositionY = EntityY(EEntity,1)
			EPositionZ = EntityZ(EEntity,1)
			
			EAngleX = EntityPitch(EEntity,1)
			EAngleY = EntityYaw(EEntity,1)
			EAngleZ = EntityRoll(EEntity,1)
			
			If EFrozen = False
				If EEmit And EWaitA = 0 Then
					CreateParticle EEntity
				EndIf
				EWaitA = EWaitA + DeltaTime
				If EWaitA >= EWaitSpan Then
					EWaitA = 0
					EWaitSpan = EDWaitSpan+Rand(-EWaitSpanJitter,EWaitSpanJitter)
				EndIf
				If EActive > -1 Then
					EActive = EActive - 1
					If EActive = 0 Then
						EActive = -1
						StopEmitter( EEntity )
						If EFreeOnEndActive >= 1 Then KillIt = True
					EndIf
				EndIf
				If EEmitSound <> 0 And EEmitSoundChannel <> 0 And ELoopEmitSound > 0 And EEmit = 1 Then
					If ChannelPlaying( EEmitSoundChannel ) <= 0 Then EEmitSoundChannel = PlaySound( EEmitSound )
				ElseIf EEmitSound <> 0 And EEmitsoundChannel = 0 And EEmit = 1 Then
					EEmitSoundChannel = PlaySound( EEmitSound )
				ElseIf EEmitSoundChannel <> 0 And EEmit = 0 And ELoopEmitSound = 1 Then
					StopChannel( EEmitSoundChannel )
				EndIf
				
				If EEmitSoundChannel <> 0 And EEmitSoundRange > 0 Then
					Vol# = EntityDistance( EEntity, gLotusCamera ) / EEmitSoundRange
					If Vol# > 1 Then Vol = 1
					If Vol# < 0 Then Vol = 0
					Vol# = 1.0 - Vol
					ChannelVolume( EEmitSoundChannel, Vol# )
				EndIf
			EndIf
			
			EWaitB = EWaitB + DeltaTime
			EWaitC = EWaitC + DeltaTime
			If EWaitB > EWaitSpan Then EWaitB = 0
			If EWaitC > EWaitSpan Then EWaitC = 0
				
			If KillIt = True Then KillLotusEmitter( EEntity )
		Next
	;	gLotusUpdateTimes( updTimeEmit ) = MilliSecs() - gLotusUpdateTimes( updTimeEmit )
		
		For LD.LotusDeflector = Each LotusDeflector
			If LDActive Then
				LDPositionX = EntityX(LDEntity,True)
				LDPositionY = EntityY(LDEntity,True)
				LDPositionZ = EntityZ(LDEntity,True)
			EndIf
		Next
		
	;	gLotusUpdateTimes( updTimePart ) = MilliSecs()
		For P.LotusParticle = Each LotusParticle
			If PLife >= 0 Then
				
				N = 0
				Decay# = 1.0
				While N < DeltaTime*(Not PFrozen)
					If PTrail <> Null Then
						If PTrailWaitC <= 0 Then
							PositionEntity PTrailEntity,PPositionX,PPositionY,PPositionZ,1
							RotateEntity PTrailEntity,PAngleX,PAngleY,0,1
							CreateParticle(PTrailEntity)
							RotateEntity PTrailEntity,PTrailAngleX,PTrailAngleY,PTrailAngleZ,1
							PositionEntity PTrailEntity,PTrailPositionX,PTrailPositionY,PTrailPositionZ,1
						EndIf
					EndIf
					D# = Max(DeltaTime-N,1)
					LFrom# = PLife/PLifeSpan
					LTo# = 1.0 - LFrom#
					
					PLastPositionX = PPositionX
					PLastPositionY = PPositionY
					PLastPositionZ = PPositionZ
					
					PPositionX = PPositionX + PTranslationX*D
					PPositionY = PPositionY + PTranslationY*D
					PPositionZ = PPositionZ + PTranslationZ*D
					
					PGravity = (PGravity - (.1*PWeight)*D)*PGravityEnabled
					PPositionY = PPositionY + PGravity*D
					
					OPitch# = PAngleX
					OYaw# = PAngleY
					
					If PSplineMesh = 0 Then
						PAngleX = PAngleX + (PAngleVelocityX + PAngleAccelerationX*LTo)*D
						PAngleY = PAngleY + (PAngleVelocityY + PAngleAccelerationY*LTo)*D
					Else
						Surface = GetSurface( PSplineMesh, 1 )
						Vertices = CountVertices( Surface ) - 1
						Vertex = Int( Vertices * LTo )
						If Vertex <= 0 Then Vertex = Vertex + 1
						NX# = VertexX( Surface, Vertex - 1 ) - VertexX( Surface, Vertex )
						NY# = VertexY( Surface, Vertex - 1 ) - VertexY( Surface, Vertex )
						NZ# = VertexZ( Surface, Vertex - 1 ) - VertexZ( Surface, Vertex )
						RotateEntity PSplineMesh,OPitch,OYaw,0
						TFormNormal -NX,-NY,-NZ,PSplineMesh,0
						AlignToVector gLotusParticlePivot,TFormedX(),TFormedY(),TFormedZ(),3,1
						PAngleX = EntityPitch( gLotusParticlePivot, 1 )
						PAngleY = EntityYaw( gLotusParticlePivot, 1 )
					EndIf
					
					PAngleZ = PAngleZ + (PAngleVelocityZ + PAngleAccelerationZ*LTo)*D
					
					If PAngleX <> OPitch Or PAngleY <> OYaw Then
						RotateEntity gLotusParticlePivot,PAngleX,PAngleY,0
						TFormVector POVelocityX,POVelocityY,POVelocityZ,gLotusParticlePivot,0
						PVelocityX = TFormedX()
						PVelocityY = TFormedY()
						PVelocityZ = TFormedZ()
					EndIf
					
					If PSplineMesh <> 0 Then
						PAngleX = OPitch
						PAngleY = OYaw
					EndIf
					
					If PVelocityDecay# <> 0 Then
						Decay# = (PVelocityDecay*LFrom)
					EndIf
					
	;				MoveEntity gLotusParticlePivot,((PVelocityX+(PAccelerationX*LTo))*Decay)*D,((PVelocityY+(PAccelerationY*LTo))*Decay)*D,((PVelocityZ+(PAccelerationZ*LTo))*Decay)*D
					
					If PDeflectorsAffect Then
						PDeflectorSpeedX = PDeflectorSpeedX * .98
						PDeflectorSpeedY = PDeflectorSpeedY * .98
						PDeflectorSpeedZ = PDeflectorSpeedZ * .98
						
						PositionEntity gLotusParticlePivot,PPositionX,PPositionY,PPositionZ
						
						For LD.LotusDeflector = Each LotusDeflector
							If LDActive = True And LDStrength <> 0 And LDRadius > 0 Then
								Distance# = EntityDistance(LDEntity,gLotusParticlePivot)
								
								If Distance# < LDRadius Then
									Magnitude# = (1.0 - (Distance# / LDRadius))*LDStrength
									If PWeight <> 0 Then Magnitude# = Magnitude# * PWeight
										
									DX# = PPositionX - LDPositionX
									DY# = PPositionY - LDPositionY
									DZ# = PPositionZ - LDPositionZ
									
									PDeflectorSpeedX = PDeflectorSpeedX + DX * Magnitude
									PDeflectorSpeedY = PDeflectorSpeedY + DY * Magnitude
									PDeflectorSpeedZ = PDeflectorSpeedZ + DZ * Magnitude
								EndIf
							EndIf
						Next
					EndIf
					
					PPositionX = PPositionX + ((PVelocityX+(PAccelerationX*LTo))*Decay)*D + PDeflectorSpeedX*D
					PPositionY = PPositionY + ((PVelocityY+(PAccelerationY*LTo))*Decay)*D + PDeflectorSpeedY*D
					PPositionZ = PPositionZ + ((PVelocityZ+(PAccelerationZ*LTo))*Decay)*D + PDeflectorSpeedZ*D
					
					If PMinY <> 0 Then
						If PPositionY <= PMinY And PBounce > 0 Then
							PBounces = PBounces + 1
							
							If PBounceMax > 0 And PBounces > PBounceMax Then
								KillIt = True
								Exit
							EndIf
							
							PPositionY = PMinY + .01
							
							PVelocityX = PVelocityX * PBounceDecay
							PVelocityY = PVelocityY * PBounceDecay
							PVelocityZ = PVelocityZ * PBounceDecay
							
							PGravity = -PGravity*(PBounceDecay*1.3)
							
							If PBounceSound <> 0 Then PBounceSoundChannel = PlaySound( PBounceSound )
						ElseIf PPositionY <= PMinY And PBounce = 0 Then
							KillIt = True
							Exit
						EndIf
					EndIf
					
					Select PLifeMode
						Case 1
							PLife = PLife - D#
						Case 2
							PLife = PLifeSpan - (ET - PLifeBegan)
					End Select
					
					N = N + 1
				Wend
				
				If KillIt = True Then
					KillParticle P
					KillIt = False
				ElseIf PBlendMode <> 1 Or PSorting = False
					DrawLotusParticle P,gLotusTPivot
				EndIf
			Else
				KillParticle P
			EndIf
		Next
	;	gLotusUpdateTimes( updTimePart ) = MilliSecs() - gLotusUpdateTimes( updTimePart )
	EndIf
	
;	gLotusUpdateTimes( updTimeSort ) = MilliSecs()
	SortParticles()
;	gLotusUpdateTimes( updTimeSort ) = MilliSecs() - gLotusUpdateTimes( updTimeSort )
	
;	gLotusUpdateTimes( updTimeDrawAlpha ) = MilliSecs()
	For HJ = 0 To gLotusAlphaParticleCount - 1
		DrawLotusParticle Object.LotusParticle( gAlphaPartArray( HJ, 1 ) ), gLotusTPivot
	Next
;	gLotusUpdateTimes( updTimeDrawAlpha ) = MilliSecs() - gLotusUpdateTimes( updTimeDrawAlpha )
	
;	gLotusUpdateTimes( uptTimeAll ) = MilliSecs() - gLotusUpdateTimes( uptTimeAll )
End Function


Comments :


big10p(Posted 1+ years ago)

 Incomplete code listing, Noel. Looks like you've hit the limit imposed on archive entries. You'll have to break it down into 2 or more listings.