Suite à la remarque de cet insolent personnage, j'ai repris une procédure de gestion de particules que j'avais faite il y a quelques années avec des sprites que j'ai adapté de maniére à fonctionner en mode Polygon si cher à SPH.
Code : Tout sélectionner
EnableExplicit
;Particle - Colorset
Structure NewColorSet
Color.i
EndStructure
;Particle - Range
Structure NewRange
Minimum.f
Maximum.f
EndStructure
;Particle - Particle Structure
Structure NewParticle
Actif.i
x.f
y.f
vx.f
vy.f
Size.f
Rotate.f
Color.i
Opacity.f
LifeTime.i
EndStructure
;-Particle - Emitter setup
Structure NewEmitter
Actif.b
Sprite.i
Type.i ;#PB_Particle_Box ou #PB_Particle_Point
x.i
y.i
Width.i
Height.i
Rate.i
LifeTime.i
vx.NewRange
vy.NewRange
Size.NewRange
Rotate.NewRange
Color.NewRange
List ColorSet.NewColorSet()
List Particle.Newparticle()
Loop.b ;Not operational
EndStructure
Global NewMap Emitters.NewEmitter()
;-
;- Private
Procedure RandomSign()
ProcedureReturn Random(1)*2-1
EndProcedure
Procedure.f RandomFloat(Maximum.f, Minimum.f)
If Maximum < Minimum
Swap Maximum, Minimum
EndIf
ProcedureReturn (Minimum+ValF("0."+Str(Random(999)))*(Abs(Maximum-Minimum)))
EndProcedure
Procedure UpdateEmitter(Emitter.s, Rate)
Protected n, NumberOfcolor.i
NumberOfcolor = ListSize(Emitters()\ColorSet())
ClearList(Emitters()\Particle())
With Emitters()\Particle()
For n=0 To Rate
AddElement(Emitters()\Particle())
If Emitters()\Type = #PB_Particle_Box
\x = 0
\y = 0
Else
\x = #PB_Ignore
\y = #PB_Ignore
EndIf
\vx = RandomFloat(Emitters()\vx\Maximum, Emitters()\vx\Minimum)
\vy = RandomFloat(Emitters()\vy\Maximum, Emitters()\vy\Minimum)
\Size = Random(Emitters()\Size\Maximum, Emitters()\Size\Minimum)
\Rotate = RandomFloat(Emitters()\Rotate\Maximum, Emitters()\Rotate\Minimum)
;Color random
SelectElement(Emitters()\ColorSet(), Random(NumberOfcolor-1))
;Particle color
\Color = Emitters()\ColorSet()\Color
;Reset Lifetime of the particle
\LifeTime = 0
\Opacity = 1
\Actif = #True
Next
EndWith
EndProcedure
;-
;- Public
Procedure EmitterCreate(Emitter.s, Type = #PB_Particle_Box, Sprite = #PB_Ignore, Width=#PB_Ignore, Height=#PB_Ignore)
Protected Gadget = GetActiveGadget()
If Width = #PB_Ignore
Width = GadgetWidth(Gadget)
EndIf
If Height = #PB_Ignore
Height = GadgetHeight(Gadget)
EndIf
;Add emitter
AddMapElement(Emitters(), Emitter)
With Emitters()
;\Sprite = Sprite
\Type = Type ;#PB_Particle_Box or #PB_Particle_Point or #PB_Ignore
\x = 0
\y = 0
\Size\Minimum = 15
\Size\Maximum = 15
\Width = Width
\Height = Height
\Rate = 50
\LifeTime = 50
If \type = #PB_Particle_Box Or #PB_Ignore
\vy\Minimum = Random(10, 5)
\vy\Maximum = Random(10, 5)
Else
\vy\Minimum = Random(10, 5) * -1
\vy\Maximum = Random(10, 5) * -1
EndIf
\Color\Minimum = RGBA(255, 0, 0, 255)
\Color\Maximum = RGBA(255, 0, 0, 255)
;Create ColorsSet
AddElement(\ColorSet())
\ColorSet()\Color = RGBA(255, 0, 0, 255)
;Update emitter
UpdateEmitter(Emitter, \Rate)
\Actif = #True
EndWith
EndProcedure
Procedure ParticleRate(Emitter.s, Rate)
FindMapElement(Emitters(), Emitter)
Emitters()\Rate = Rate
UpdateEmitter(Emitter, Rate)
EndProcedure
Procedure ParticleTimeToLife(Emitter.s, LifeTime)
FindMapElement(Emitters(), Emitter)
Emitters()\LifeTime = LifeTime
UpdateEmitter(Emitter, Emitters()\Rate)
EndProcedure
Procedure ParticleSpeedRange(Emitter.s, vx1.f, vy1.f, vx2.f=#PB_Ignore, vy2.f=#PB_Ignore)
If vx2 = #PB_Ignore
vx2 = vx1
EndIf
If vy2 = #PB_Ignore
vy2 = vy1
EndIf
FindMapElement(Emitters(), Emitter)
Emitters()\vx\Minimum = vx1
Emitters()\vx\Maximum = vx2
Emitters()\vy\Minimum = vy1
Emitters()\vy\Maximum = vy2
ForEach Emitters()\Particle()
Emitters()\Particle()\vx = RandomFloat(Emitters()\vx\Maximum, Emitters()\vx\Minimum)
Emitters()\Particle()\vy = RandomFloat(Emitters()\vy\Maximum, Emitters()\vy\Minimum)
Next
EndProcedure
Procedure ParticleSizeRange(Emitter.s, Minimum.f, Maximum.f = #PB_Ignore)
If Maximum = #PB_Ignore
Maximum = Minimum
EndIf
FindMapElement(Emitters(), Emitter)
Emitters()\Size\Maximum = Maximum
Emitters()\Size\Minimum = Minimum
ForEach Emitters()\Particle()
Emitters()\Particle()\Size = Random(Emitters()\Size\Maximum, Emitters()\Size\Minimum)
Next
EndProcedure
Procedure ParticleRotateRange(Emitter.s, Minimum.f, Maximum.f = #PB_Ignore)
If Maximum = #PB_Ignore
Maximum = Minimum
EndIf
FindMapElement(Emitters(), Emitter)
Emitters()\Rotate\Minimum = Minimum
Emitters()\Rotate\Maximum = Maximum
ForEach Emitters()\Particle()
Emitters()\Particle()\Rotate = RandomFloat(Emitters()\Rotate\Maximum, Emitters()\Rotate\Minimum)
Next
EndProcedure
;Changes the particles color range for the particle emitter
Procedure ParticleColorsRange(ParticleEmitter.s, Color1, Color2=#PB_Ignore, NumberOfcolor=1)
Protected r1, g1, b1
Protected r2, g2, b2
Protected dr, dg, db
Protected i
If Color2 = #PB_Ignore
Color2 = Color1
EndIf
;Start color
r1 = Red(Color1)
g1 = Green(Color1)
b1 = Blue(Color1)
;Finish color
r2 = Red(Color2)
g2 = Green(Color2)
b2 = Blue(Color2)
;For each channel, calculating the differenciated between each hue (NumberOfColor is the number of tones).
dr = Int((r2 - r1) / NumberOfcolor)
dg = Int((g2 - g1) / NumberOfcolor)
db = Int((b2 - b1) / NumberOfcolor)
;Creation of the color spectrum
FindMapElement(Emitters(), ParticleEmitter)
;Stores the minimum and maximum colors
Emitters()\Color\Minimum = Color1
Emitters()\Color\Maximum = Color2
ClearList(Emitters()\ColorSet())
For i = 0 To NumberOfcolor - 1
r2 = r2 - dr
g2 = g2 - dg
b2 = b2 - db
AddElement(Emitters()\ColorSet())
Emitters()\ColorSet()\Color = RGBA(r2, g2, b2, 255)
Next
;For each particle, assign a color
ForEach Emitters()\Particle()
SelectElement(Emitters()\ColorSet(), Random(NumberOfcolor-1))
Emitters()\Particle()\Color = Emitters()\ColorSet()\Color
Next
EndProcedure
Procedure EmitterPlay(Emitter.s, x = 0, y = 0, Loop = #True)
Protected Actif = #False
Protected Gadget = GetActiveGadget()
If FindMapElement(Emitters(), Emitter)
SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
ForEach Emitters()\Particle()
With Emitters()\Particle()
If \LifeTime <= 0 And \Actif = #True
If Loop = #False
\Actif = #False
EndIf
\LifeTime = Random(Emitters()\LifeTime)
\Opacity = 1
If Emitters()\Type = #PB_Particle_Box
\x = Random(Emitters()\Width) + x
\y = y
ElseIf Emitters()\Type = #PB_Particle_Point
\x = x
\y = y
Else
\x = Random(Emitters()\Width) - Random(Emitters()\Width)
\y = Random(Emitters()\Height) - Random(Emitters()\Height)
EndIf
EndIf
\x + \vx
\y + \vy
If \LifeTime > 0
Actif = #True
If \LifetIme < 30 And \Opacity > 0
\Opacity - 0.1
EndIf
glMatrixMode_(#GL_MODELVIEW)
glPushMatrix_();
glLoadIdentity_()
; Rotation
glTranslatef_(\x + \Size * 0.5, \y + \Size * 0.5, 0)
glRotatef_(\rotate, 0, 0, 1)
glTranslatef_(-\x - \Size * 0.5, -\y - \Size * 0.5, 0)
glColor4f_(Red(\Color)/255, Green(\Color)/255, Blue(\Color)/255, \Opacity)
glBegin_(#GL_POLYGON)
glVertex2f_(\x, \y)
glVertex2f_(\x+\size, \y)
glVertex2f_(\x+\size, \y+\size)
glVertex2f_(\x, \y+\size)
glEnd_()
glPopMatrix_()
EndIf
\LifeTime - 1
EndWith
Next
Emitters()\Actif = Actif
EndIf
EndProcedure
Procedure EmitterScroll(Emitter.s, x, y)
If FindMapElement(Emitters(), Emitter)
ForEach(Emitters()\Particle())
With Emitters()\Particle()
\x + x
\y + y
EndWith
Next
EndIf
EndProcedure
DisableExplicit
puis sauvegarder ce code dans le même dossier que "Particle.pbi".
Code : Tout sélectionner
EnableExplicit
IncludeFile "Particle.pbi"
;Structure d'un vecteur 2D
Structure newVector
x.f
y.f
EndStructure
Global A.newVector, B.newVector, C.newVector
;Distance et vitesse de déplacement
Global Distance.f, Speed.f = 100
;Nombre d'iterations à effectuer pour aller de A à B
Global N.f
Global Scene, ww = 1024, wh = 600
; Plan de l'application
Declare Start()
Declare Render()
Declare Sky(Gadget, Color, Stars.i = 100, StarColor = $FFFFFFFF , OpacityMin.f=0.5, SizeMin = 1, SizeMax = 3)
Declare DrawMoon(Gadget, x.f, y.f, Width.f, Height.f, Fullness.f = 1, Color.i = $FFFFFFFF, Angle.f = 0)
Declare Mountain(Gadget, x.f, y.f, Width.f, Ranges.s, Color.i = $FFFD47FF)
Declare.d Distance(*p.Point, *q.Point)
Declare Exit()
Start()
;-
Procedure Start()
C\y = wh
OpenWindow(#PB_Any, 0, 0, ww, wh, "OpenGL : Création d'une scene", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
; Fenetre openGl
Scene = OpenGLGadget(#PB_Any, 0, 0, ww, wh, #PB_OpenGL_Keyboard)
SetActiveGadget(Scene)
; Activation textures et transparence
glEnable_(#GL_BLEND)
glBlendFunc_(#GL_SRC_ALPHA, #GL_ONE_MINUS_SRC_ALPHA)
; Couleur d'arriere plan
; Chaque composant RGBA est divisé par 255
glClearColor_(0, 0, 0, 1.0)
; Sélectionner la pile des matrices de projection
glMatrixMode_(#GL_PROJECTION)
; Ré-initialise la matrice de projection
; et assure ainsi qu’une seule projection soit effectuée.
glLoadIdentity_()
gluOrtho2D_(0, ww, wh, 0)
glDisable_(#GL_DEPTH_TEST)
glMatrixMode_(#GL_MODELVIEW);
glLoadIdentity_()
;- Création de l'émetteur de particules
EmitterCreate("ShootingStar", #PB_Particle_Point)
ParticleRate("ShootingStar", 200)
ParticleColorsRange("ShootingStar", RGB(255, 255, 0), RGB(0, 255, 255), 20)
ParticleSizeRange("ShootingStar", 1, 3)
ParticleSpeedRange("ShootingStar", -0.3, -0.3, 0.3, 0.3)
ParticleTimeToLife("ShootingStar", 100)
; Déclencheur
BindEvent(#PB_Event_CloseWindow, @Exit())
; Boucle de rendu visuel
Render()
EndProcedure
; Visualisation du résultat
Procedure Render()
Protected Dx.f, Dy.f
Repeat
; Quelle est la position de l'étoile filante (Point C)
If C\y >= wh
;l'étoile filante atteint le bas de l'écran
;Définition du point A
;Position en haut de l'écran (X aléatoire)
A\x = Random(ww)
A\y = 0
;Définition du point B
;Position en bas de l'écran (X aléatoire)
B\x = Random(ww)
B\y = wh
;Point de départ de l'étoile filante
;Position en haut de l'écran (X aléatoire)
C\x = A\x
C\y = 0
;Distance entre les points B et A
Distance = Distance(A, B)
;En divisant la distance par la variable Speed on obtient la durée
;Cette durée correspondra au nombre "N" d'itérations à effectuer
N = Sqr(Distance) / Speed
;Diviser la distance horizontale par le nombre d'itérations pour savoir combien de pixels on ajoute à X à chaque itération, idem pour Y.
Dx = (B\x - A\x) / N
Dy = (B\y - A\y) / N
Else
;Déplacement de l'étoile filante (Point C) entre A et B
If C\x < B\x Or C\y < B\y
C\x = C\x + Dx
C\y = C\y + Dy
EndIf
EndIf
; Efface le frame buffer et le Z-buffer
glClear_(#GL_COLOR_BUFFER_BIT | #GL_DEPTH_BUFFER_BIT)
; Ciel
Sky(Scene, RGBA(36, 69, 68, 255), 100, RGBA(255, 255, 255, 255), 0.1)
; Lune
DrawMoon(Scene, 200, 150, 50, 50 , -0.8, RGBA(255, 255, 255, 255), 180)
; Dessin de l'étoile filante
glBegin_(#GL_POLYGON)
glVertex2f_(C\x, C\y)
glVertex2f_(C\x + 4, C\y)
glVertex2f_(C\x + 4, C\y + 4)
glVertex2f_(C\x, C\y + 4)
glEnd_()
EmitterPlay("ShootingStar", C\x, C\y)
; Relief
Mountain(Scene, 0, 0, ww, "[100, 50, 60, 125, 130, 200, 250, 280, 300, 225, 200, 125, 300, 200, 210]", RGBA(21, 21, 21, 255))
Mountain(Scene, 0, 0, ww-200, "[100, 10, 30, 125, 80, 90, 100, 50, 80, 65, 60, 55, 40, 20, 0]", RGBA(0, 0, 0, 255))
Mountain(Scene, 0, 0, ww, "[10, 15, 20, 40, 35, 30, 35, 40, 35, 30, 0]", RGBA(67, 5, 59, 255))
; FlipBuffers
SetGadgetAttribute(Scene, #PB_OpenGL_FlipBuffers, #True)
Until WindowEvent() = #PB_Event_CloseWindow
EndProcedure
; Dessin d'une lune
Procedure DrawMoon(Gadget, x.f, y.f, Width.f, Height.f, Fullness.f = 1, Color.i = $FFFFFFFF, Angle.f = 0)
Protected Finesse.f = 0.1
Protected n.f = Finesse
Protected SinAngle.f
Protected CosAngle.f
Protected x0.f
Protected y0.f
SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
glMatrixMode_(#GL_MODELVIEW)
glPushMatrix_();
; Location
glTranslatef_(x, y, 0)
; Rotate
glRotatef_(Angle, 0, 0, 1)
; Draw Moon
glBegin_(#GL_QUAD_STRIP)
glColor4f_(Red(Color)/255, Green(Color)/255, Blue(Color)/255, Alpha(Color)/255)
While n < #PI
SinAngle.f = Sin(n)
CosAngle.f = Cos(n)
x0 = (Width * SinAngle)
y0 = (Height * CosAngle)
glVertex2f_(x0, y0);
glVertex2f_(-Fullness * x0, y0)
n + Finesse
Wend
glEnd_()
glPopMatrix_()
EndProcedure
; Dessin d'un ciel étoilé
Procedure Sky(Gadget, Color, Stars.i = 100, StarColor = $FFFFFFFF , OpacityMin.f=0.5, SizeMin = 1, SizeMax = 3)
Structure Star
x.f
y.f
EndStructure
Protected w = GadgetWidth(Gadget)
Protected h = GadgetHeight(Gadget)
Static Dim Stars.Star(100), Flag.b
Protected n
; Initialisation des étoiles
If Flag = 0
Flag = 1
For n = 0 To Stars
Stars(n)\x = Random(w)
Stars(n)\y = Random(h)
Next
EndIf
; Dessin du ciel
SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
glMatrixMode_(#GL_MODELVIEW)
glLoadIdentity_()
glPushMatrix_()
; Couleur du ciel
glClearColor_(Red(Color)/255, Green(Color)/255, Blue(Color)/255, Alpha(Color)/255)
; Dessin des étoiles
For n = 1 To Stars
glPointSize_(Random(SizeMax, SizeMin)) ; Valeur decimal
glColor4f_(Red(StarColor)/255, Green(StarColor)/255, Blue(StarColor)/255, (Random(10, OpacityMin * 10))/10)
glBegin_(#GL_POINTS)
glVertex2f_(Stars(n)\x, Stars(n)\y)
glEnd_()
Next
glPopMatrix_()
EndProcedure
; Dessin d'un relief montagneux
Procedure Mountain(Gadget, x.f, y.f, Width.f, Ranges.s, Color.i = $FFFD47FF)
Protected gh = GadgetHeight(Gadget)
Protected Dim Ranges(0), n, s, i.i, x0.f
ParseJSON(0, Ranges)
ExtractJSONArray(JSONValue(0), Ranges())
; Nombre de points à dessiner
s = ArraySize(Ranges())
; Intervalle entre chaque point
i = (Width / s)
; Dessin du ciel
SetGadgetAttribute(Gadget, #PB_OpenGL_SetContext, #True)
glMatrixMode_(#GL_MODELVIEW)
glLoadIdentity_()
glPushMatrix_()
glBegin_(#GL_POLYGON)
glColor4f_(Red(Color)/255, Green(Color)/255, Red(Color)/255, Alpha(Color)/255)
glVertex2f_(x, wh-y)
For n = 0 To s
glVertex2f_(x0, gh-y-Ranges(n))
x0 + i
Next
glVertex2f_(width, gh-y)
glEnd_()
glPopMatrix_()
EndProcedure
; Distance entres deux points
Procedure.d Distance(*p.Point, *q.Point)
Protected Distance.d, dx.d, dy.d
;Distance horizontale
dx = *p\x - *q\x
;Distance verticale
dy = *p\y - *q\y
;Théoréme de Pythagore
Distance = Sqr(dx*dx + dy*dy )
ProcedureReturn Distance
EndProcedure
Procedure Exit()
End
EndProcedure