EnableExplicit

;#LargePeaks = 1
#PeaksCountMax = 360 * 4
#PeaksCountMaxX = #PeaksCountMax - 1
#PeaksCountMaxStereoAS = #PeaksCountMax * 2 - 1
#RenderMainInfoMySelf = 2
#PartID = 51886 ; RaveN/Rabennest / stars/encircle+1
#MaxTick = $20000
#LargeRects = 1
CompilerIf #RenderMainInfoMySelf = 2
  Global TransparentCenterMul.f = 0.66
  CompilerEndIf


#ParticleRenderCountMax = #PeaksCountMax * 2
#ParticleRenderCountMaxX = #ParticleRenderCountMax - 1

Global Dim xLSData.f(359)


Declare RenderSelfPart(SkipFrame.l, xElapsedTicks.l)
IncludeFile "LSDemo (Particles).pb"

;#RaveNColShift1 = 225 ; 225
#RaveNColShift1 = #False

CompilerIf #RaveNColShift1
  #RaveNColShift2 = #RaveNColShift1 * 766 / 360

  Procedure.l StepToDataIndex(Index.f)
    Define.l xLong1 = Round(Index, #PB_Round_Down)
    ProcedureReturn (2 * 360 - (xLong1 + #RaveNColShift1)) % 360
    EndProcedure
  CompilerEndIf

Procedure.l SplitCol(Saturation.f, Phase.l)
  Define.l BeamR
  Define.l BeamG
  Define.l BeamB
  Define.l BeamS
  
  CompilerIf #RaveNColShift1  
    Phase = (2 * 766 - (Phase + #RaveNColShift2)) % 766
    CompilerEndIf
  If Saturation > MaxInit / 100: Saturation = MaxInit / 100: EndIf
  BeamS = Sqr(1 - Saturation) * 80 * MaxInit / 100

  Select Phase
    Case 0 To 255
      BeamR = BeamR
      BeamG = Saturation * Phase + BeamS
      If BeamG > 255: BeamG = 255: EndIf
      BeamB = Saturation * (255 - Phase) + BeamS
      If BeamB > 255: BeamB = 255: EndIf
    Case 256 To 510
      BeamR = Saturation * (Phase - 255) + BeamS
      If BeamR > 255: BeamR = 255: EndIf
      BeamG = Saturation * (511 - Phase) + BeamS
      If BeamG > 255: BeamG = 255: EndIf
      BeamB = BeamS
    Case 511 To 765
      BeamR = Saturation * (766 - Phase) + BeamS
      If BeamR > 255: BeamR = 255: EndIf
      BeamG = BeamS
      BeamB = Saturation * (Phase - 510) + BeamS
      If BeamB > 255: BeamB = 255: EndIf
    EndSelect

  ProcedureReturn BeamB * $10000 + BeamG * $100 + BeamR
  EndProcedure

Procedure.f Fix(xSng1.f)
  ProcedureReturn Round(xSng1, #PB_Round_Down)
  EndProcedure

Procedure RenderAdd(PosX.l, PosY.l, Saturation.f, Phase.f)
  Define.l xSize
  Define.l Col
  Define.f X1
  Define.l X2

  ;Saturation = Saturation * Saturation * 150 * MaxInit / 100
  Saturation = Saturation * 88 * MaxInit / 100 * ParticleCenterY / 480
  xSize = Saturation
  If xSize > 7: xSize = 7: EndIf
  If xSize < 1: xSize = 1: EndIf
  If xSize > 1: Saturation = Saturation / (xSize - 1): EndIf
  X1 = Fix(Phase)
  Col = SplitCol(Saturation, X1)

  ;If Col
    With ParticleRenderData(ParticleRenderCount)
      \Left = PosX - xSize / 2
      \Top = PosY - xSize / 2
      \Right = \Left + xSize
      \Bottom = \Top + xSize
      \Brush = Col
      EndWith
    OptimizeAndAddRect()
  ;  End If
  EndProcedure

Procedure.f xMOD360(xSng1.f)
  Define.f xSng2 = Round(xSng1 / 360, #PB_Round_Down) * 360
  ProcedureReturn xSng1 - xSng2
  EndProcedure

Procedure.f Mixed(xFrom.f, xTo.f, xStep.f, MaxStep)
  xFrom = (xFrom * (MaxStep - MaxStep)) / MaxStep
  xTo = (xTo * xStep) / MaxStep
  ProcedureReturn xFrom + xTo
  EndProcedure

Macro BeginPLoop()
  xLong1 = 0
  While xLong1 < 360
  xStep2 = xMOD360(xLong1 + xStep + PreStep)
  If xStep2 > 180: xStep2 = 360 - xStep2: EndIf
  EndMacro

Macro MixXY()
  NewValueX = (xStep * NewValueX) / 360 + ((360 - xStep) * OldValueX) / 360
  NewValueY = (xStep * NewValueY) / 360 + ((360 - xStep) * OldValueY) / 360
  EndMacro

Macro RenderPhased()
  xStep2 = Fix(xLong1)
  CompilerIf #RaveNColShift1
    RenderAdd(NewValueX, NewValueY, xLSData(StepToDataIndex(xStep2)), Fix(xLong1 / 360 * 766))
    CompilerElse
    RenderAdd(NewValueX, NewValueY, xLSData(xStep2), Fix(xLong1 / 360 * 766))
    CompilerEndIf
  EndMacro

Macro RenderMatrixIn()
  ;OldValueX = Fix(xStep / 360 * 766)
  OldValueX = Fix(xMod360(xStep + 165) / 360 * 766)
  If xStep < 60
    OldValueY = Fix(xLong1 / 360 * 766)
    OldValueX = OldValueX * 0.75 * (xStep / 60) + OldValueY * ((60 - xStep) / 60)
    EndIf

  xStep2 = Fix(xLong1)
  CompilerIf #RaveNColShift1
    RenderAdd(NewValueX, NewValueY, xLSData(StepToDataIndex(xStep2)), OldValueX)
    CompilerElse
    RenderAdd(NewValueX, NewValueY, xLSData(xStep2), OldValueX)
    CompilerEndIf
  EndMacro

Macro RenderMatrixOut()
  OldValueX = Fix((xMod360(xStep + 165)) / 360 * 766)
  If xStep > 210
    OldValueY = Fix(xLong1 / 360 * 766)
    OldValueX = (OldValueX * 0.75 * (360 - xStep)) / 150 + (OldValueY * (xStep - 210)) / 150
    EndIf
  
  
  xStep2 = Fix(xLong1)
  CompilerIf #RaveNColShift1
    RenderAdd(NewValueX, NewValueY, xLSData(StepToDataIndex(xStep2)), OldValueX)
    CompilerElse
    RenderAdd(NewValueX, NewValueY, xLSData(xStep2), OldValueX)
    CompilerEndIf
  EndMacro

Macro EndPLoop()
  xLong1 = xLong1 + 0.25
  Wend
  EndMacro

Macro ZZCircle(RetVarX, RetVarY)
  xRX = Sin(xStep2 / 180 * #PI)
  xRY = Cos(xLong1 * 2 / 180 * #PI)
  RetVarX = ParticleCenterX + xWZ * Cos(xStep2 / 180 * #PI) * xRX
  RetVarY = ParticleCenterY + xHZ * Sin(xLong1 / 180 * #PI) * xRY
  EndMacro

Macro BaseBall(RetVarX, RetVarY)
  xRX = Cos(xStep2 / 180 * #PI)
  xRY = Sin(xLong1 * 2 / 180 * #PI)
  RetVarX = (ParticleCenterX - xWZ) + xWZ * 2 * Cos(xStep2 / 180 * #PI) * xRX
  RetVarY = ParticleCenterY + xHZ * Sin(xLong1 / 180 * #PI) * xRY
  EndMacro

Macro HyperbellIn(RetVarX, RetVarY)
  xRX = Cos(xStep2 * (xStep) / 60 / 180 * #PI)
  xRY = ATan(xStep2 / 180 * #PI)
  RetVarX = ParticleCenterX + xWZ * xRX * Cos(xStep2 * 2 / 180 * #PI) * xRX
  RetVarY = ParticleCenterY + xHZ * xRY * Sin(xLong1 * 2 / 180 * #PI) * xRY
  EndMacro

Macro HyperbellOut(RetVarX, RetVarY)
  xRX = Cos(xStep2 * (360 - xStep) / 60 / 180 * #PI)
  xRY = ATan(xStep2 / 180 * #PI)
  RetVarX = ParticleCenterX + xWZ * xRX * Cos(xStep2 * 2 / 180 * #PI) * xRX
  RetVarY = ParticleCenterY + xHZ * xRY * Sin(xLong1 * 2 / 180 * #PI) * xRY
  EndMacro

Macro ScrMatrixIn(RetVarX, RetVarY)
  If xStep < 60
    xS1 = ParticleCenterX * 0.75 * (xStep / 60) + xWZ * ((60 - xStep) / 60)
    Else
    xS1 = ParticleCenterX * 0.74
    EndIf
  RetVarX = ParticleCenterX + xS1 * 1.04 * ATan(Sin(xLong1 + xStep2 / 180 * #PI) * #PI)
  RetVarY = ParticleCenterY + xS1 * Sin(xLong1 * 8 / 180 * #PI)
  EndMacro

Macro ScrMatrixOut(RetVarX, RetVarY)
  If xStep > 300
    xS1 = ParticleCenterX * 0.75 * ((360 - xStep) / 60) + xWZ * ((xStep - 300) / 60)
    Else
    xS1 = ParticleCenterX * 0.74
    EndIf
  RetVarX = ParticleCenterX + xS1 * 1.04 * ATan(Sin(xLong1 + xStep2 / 180 * #PI) * #PI)
  RetVarY = ParticleCenterY + xS1 * Sin(xLong1 * 8 / 180 * #PI)
  EndMacro      

Macro SinDance(RetVarX, RetVarY)
  RetVarX = ParticleCenterX + xWZ / 3 * (Sin((xLong1 + xStep) * 2 / 180 * #PI) * #PI) * ATan(xStep2 / 180 * #PI)
  RetVarY = ParticleCenterY + xHZ * 0.7 * Sin(xLong1 * 8 / 180 * #PI) * Cos(xStep2 / 180 * #PI)
  EndMacro

Macro DanceParticle(RetVarX, RetVarY)
  xRX = ATan(xStep2 / 180 * #PI)
  RetVarX = ParticleCenterX + xWZ / 3 * (Sin((xLong1 * xRX + xStep) * 2 / 180 * #PI) * #PI) * ATan(xStep2 / 180 * #PI)
  RetVarY = ParticleCenterY + xHZ * 0.7 * Sin(xLong1 * 2 * xRX / 180 * #PI) * Cos(xStep2 / 180 * #PI)
  EndMacro

Procedure RenderSelfPart(SkipFrame.l, xElapsedTicks.l)
  Define.f xLong1
  Define.l Index
  Define.l NewValueX
  Define.l NewValueY
  Define.l OldValueX
  Define.l OldValueY
  Define.l xWZ
  Define.l xHZ
  Define.f xS1
  Define.f xS2
  Define.f xRX
  Define.f xRY
  Define.l xStep2
  Define.f xCol
  Define.f PreStep
  Static xStep.l
  Static xProg.l
  Define.f xLSDataS
  Static CurRot.l
  Static NotFirst.l
  
  
  ;LineSpec_GetSpectrum(@xLSData(0), 360, 0, 2, 0)
  ;LineSpec_GetSpectrum(@xLSDataS, 1, 0, 3, 0)
  If SetWaveData(0)
    GetFullSpectrumMonoOpt(0)
    SpectrumCompactMono(0, 1024, @xLSData(0), 360)
    SpectrumCompactMono(@xLSData(0), 360, @xLSDataS, 1)
    EndIf
  
  CompilerIf 1
    If NotFirst
      CurRot = (CurRot + xElapsedTicks) & #MaxTickAND
      EndIf
    NotFirst = #True

    xProg = Round((8 * CurRot) / #MaxTick, #PB_Round_Down)
    xStep = (8 * 360 * CurRot) / #MaxTick - xProg * 360
    CompilerElse
    xStep = (xStep + 1) % 360
    If xStep = 0
      xStep = 0
      xProg = (xProg + 1) % 8
      EndIf
    CompilerEndIf
  
  xWZ = ParticleCenterX * (Fix(xLSDataS * 10 * MaxInit / 100) / 3 + 0.5) / 1.5
  xHZ = ParticleCenterY * (Fix(xLSDataS * 10 * MaxInit / 100) / 3 + 0.5) / 1.5
  PreStep = (xLSDataS * 120 * MaxInit / 100 + 0.25)

  Select xProg
    Case 0
      BeginPLoop()
      ZZCircle(NewValueX, NewValueY)
      RenderPhased()
      EndPLoop()
    Case 1
      BeginPLoop()
      ZZCircle(OldValueX, OldValueY)
      BaseBall(NewValueX, NewValueY)
      MixXY()
      RenderPhased()
      EndPLoop()
    Case 2
      BeginPLoop()
      BaseBall(OldValueX, OldValueY)
      HyperbellIn(NewValueX, NewValueY)
      MixXY()
      RenderPhased()
      EndPLoop()
    Case 3
      BeginPLoop()
      HyperbellOut(NewValueX, NewValueY)
      RenderPhased()
      EndPLoop()
    Case 4
      BeginPLoop()
      HyperbellIn(OldValueX, OldValueY)
      ScrMatrixIn(NewValueX, NewValueY)
      MixXY()
      RenderMatrixIn()
      EndPLoop()
    Case 5
      BeginPLoop()
      ScrMatrixOut(OldValueX, OldValueY)
      SinDance(NewValueX, NewValueY)
      MixXY()
      RenderMatrixOut()
      EndPLoop()
    Case 6
      BeginPLoop()
      SinDance(OldValueX, OldValueY)
      DanceParticle(NewValueX, NewValueY)
      MixXY()
      RenderPhased()
      EndPLoop()
    Case 7
      BeginPLoop()
      DanceParticle(OldValueX, OldValueY)
      ZZCircle(NewValueX, NewValueY)
      MixXY()
      RenderPhased()
      EndPLoop()
    EndSelect
  EndProcedure


; IDE Options = PureBasic 5.20 LTS (Windows - x86)
; CursorPosition = 80
; FirstLine = 76
; Folding = -----
; EnableAsm
; Executable = Simple spectrum x4.lpanim.dll
; DisableDebugger
; IncludeVersionInfo
; AddResource = LSDemo (Particles).rc