Code : Tout sélectionner
;:=============================================================================
;:- MoteurSprite.pbi
;:- Author : Eddy
;:- Date : September 25, 2013
;:- Compiler : PureBasic 5.20 LTS
;:- Target OS : Mac, Linux, Windows
;:- Source --------------------------------------------------------------------
;:- http://www.purebasic.fr/english/Vuetopic.php?f=40&t=56507
;;- Traduit en français par Micoute
;:=============================================================================
EnableExplicit
Structure SP_DEFORMATION
x.f[4]
y.f[4]
EndStructure
Structure SP_FRAME
u.f[4]
v.f[4]
Largeur.f
Hauteur.f
PointChaudX.f
PointChaudY.f
EndStructure
Structure SP_ATLAS
Atlas.i
Texture.i
Array Frames.SP_FRAME(0)
EndStructure
Structure SP_SPRITE
Sprite.i
*CoucheParent.SP_Couche
x.f
y.f
EchelleX.f
EchelleY.f
Angle.f
Etat.i
Frame.i
Couleurs.i[4]
*Deformer.SP_DEFORMATION
EndStructure
Structure SP_Couche
Couche.i
StructureUnion
CouchePivot.i
CoucheRoll.i
CoucheEchelle.i
EndStructureUnion
CoucheDecalage.i
CouchePosition.i
CoucheOmbre.i
Mesh.i
OmbreMesh.i
Material.i
OmbreMateriel.i
MelangeMateriel.i
FiltreMateriel.i
*Atlas.SP_ATLAS
Map *SpritesAttaches.SP_SPRITE()
*VueParent.SP_Vue
x.f
y.f
EchelleX.f
EchelleY.f
Etat.i
CouleurOmbre.i
DecalageOmbreX.f
DecalageOmbreY.f
EndStructure
Structure SP_Vue
Vue.i
VuePivot.i
DecalageVue.i
StructureUnion
VuePosition.i
VueRoll.i
EndStructureUnion
Camera.i
Map *AttachedCouches.SP_Couche()
x.f
y.f
CameraX.i
CameraY.i
LargeurCamera.i
CameraHauteur.i
DecalageX.f
DecalageY.f
EchelleX.f
EchelleY.f
EndStructure
Structure SP_MOTEUR
Map Atlases.SP_ATLAS()
Map Vues.SP_Vue()
Map Couches.SP_Couche()
Map Sprites.SP_SPRITE()
*SpriteDefaut.SP_SPRITE
*CoucheDefaut.SP_Couche
Array OrdreUV.i(3, 3)
EndStructure
Global MoteurSprite.SP_MOTEUR
Macro SP_Colon
:
EndMacro
Macro SP_Override(Function)
SP_Colon#Macro Function#SP_Colon#SP_#Function#SP_Colon#EndMacro
EndMacro
SP_Override(SpriteID)
SP_Override(PivoterSprite)
SP_Override(LibererSprite)
Enumeration
#Sprite_Cache=%1
#Sprite_RetournerX=%10
#Sprite_RetournerY=%100
#Sprite_RetournerXY=#Sprite_RetournerX|#Sprite_RetournerY
#Sprite_Desactive=%1000
#Couche_Cache=%1
#Ombre_Couche=%10
EndEnumeration
Procedure.i VueID(Vue)
ProcedureReturn FindMapElement(MoteurSprite\Vues(), ""+Vue)
EndProcedure
Procedure.i CoucheID(Couche)
ProcedureReturn FindMapElement(MoteurSprite\Couches(), ""+Couche)
EndProcedure
Procedure.i SpriteID(Sprite)
ProcedureReturn FindMapElement(MoteurSprite\Sprites(), ""+Sprite)
EndProcedure
Procedure.i AtlasID(Atlas)
ProcedureReturn FindMapElement(MoteurSprite\Atlases(), ""+Atlas)
EndProcedure
;---------- Couleur
Macro CouleurRGB(CouleurRGBA)
RGB(Red(CouleurRGBA), Green(CouleurRGBA), Blue(CouleurRGBA))
EndMacro
Macro CouleurRGBA(CouleurRGB, Alpha)
RGBA(Red(CouleurRGB), Green(CouleurRGB), Blue(CouleurRGB), Alpha)
EndMacro
;---------- ATLAS
Procedure LibererAtlas(Atlas)
Protected *Atlas.SP_ATLAS=AtlasID(Atlas)
;free resources
FreeTexture(*Atlas\Texture)
DeleteMapElement(MoteurSprite\Atlases(), ""+Atlas)
EndProcedure
Procedure.i CreerAtlas(Atlas, Largeur, Hauteur)
Protected Resultat
If Atlas=#PB_Any
Static NumeroAtlas=$FFFF : NumeroAtlas+103 : Atlas=NumeroAtlas
AddMapElement(MoteurSprite\Atlases(), ""+Atlas)
Resultat=Atlas
Else
If AtlasID(Atlas) : LibererAtlas(Atlas) : EndIf
Resultat=AddMapElement(MoteurSprite\Atlases(), ""+Atlas)
EndIf
With MoteurSprite\Atlases()
\Atlas=Atlas
\Texture=CreateTexture(#PB_Any, Largeur, Hauteur)
\Frames(0)\u[0]=0 : \Frames(0)\v[0]=0
\Frames(0)\u[1]=1 : \Frames(0)\v[1]=0
\Frames(0)\u[2]=1 : \Frames(0)\v[2]=1
\Frames(0)\u[3]=0 : \Frames(0)\v[3]=1
\Frames(0)\Largeur=Largeur
\Frames(0)\Hauteur=Hauteur
ProcedureReturn Resultat
EndWith
EndProcedure
Procedure.i ChargerAtlas(Atlas, FichierImage.s, Qualite=2)
Protected ImageTextire=LoadImage(#PB_Any, FichierImage)
Protected LargTexture=ImageWidth(ImageTextire)
Protected HautTexture=ImageHeight(ImageTextire)
If Qualite>0
;power of 2 texture size improves rendering Qualite
LargTexture=Pow(2, Round(Log(LargTexture)/Log(2), #PB_Round_Up))
HautTexture=Pow(2, Round(Log(HautTexture)/Log(2), #PB_Round_Up))
;texture square size improves compatibility with some GPU
If Qualite>1
If LargTexture<HautTexture : LargTexture=HautTexture : Else : HautTexture=LargTexture : EndIf
EndIf
EndIf
Protected Resultat=CreerAtlas(Atlas, LargTexture, HautTexture)
With MoteurSprite\Atlases()
StartDrawing(TextureOutput(\Texture))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(ImageID(ImageTextire), 0, 0)
StopDrawing()
EndWith
FreeImage(ImageTextire)
ProcedureReturn Resultat
EndProcedure
Procedure.i SortieAtlas(Atlas)
Protected *Atlas.SP_ATLAS=AtlasID(Atlas)
ProcedureReturn TextureOutput(*Atlas\Texture)
EndProcedure
Procedure.i DefinirFrameAtlas(Atlas, Frame, x, y, Largeur, Hauteur, PointChaudX=0, PointChaudY=0, EstPivote=#False)
Protected *Atlas.SP_ATLAS=AtlasID(Atlas)
With *Atlas
If Frame=#PB_Any
Frame=ArraySize(\Frames())+1
EndIf
If Frame> ArraySize(\Frames())
ReDim \Frames(Frame)
EndIf
If EstPivote : x-1 : EndIf
Protected tw.f=TextureWidth(\Texture)
Protected th.f=TextureHeight(\Texture)
Protected u0.f=x/tw, v0.f=y/th
Protected u1.f=(x+Largeur)/tw, v1.f=(y+Hauteur)/th
EndWith
With *Atlas\Frames(Frame)
If EstPivote
\u[0]=u1 : \v[0]=v0
\u[1]=u1 : \v[1]=v1
\u[2]=u0 : \v[2]=v1
\u[3]=u0 : \v[3]=v0
\Largeur=Hauteur
\Hauteur=Largeur
\PointChaudX=PointChaudY
\PointChaudY=\Hauteur-PointChaudX
Else
\u[0]=u0 : \v[0]=v0
\u[1]=u1 : \v[1]=v0
\u[2]=u1 : \v[2]=v1
\u[3]=u0 : \v[3]=v1
\Largeur=Largeur
\Hauteur=Hauteur
\PointChaudX=PointChaudX
\PointChaudY=PointChaudY
EndIf
EndWith
ProcedureReturn Frame
EndProcedure
Procedure LancerAtlas(Atlas, Marge=1)
EndProcedure
Procedure ArreterAtlas()
EndProcedure
;---------- SPRITE
Procedure LibererSprite(Sprite)
Protected *Sprite.SP_Sprite=SpriteID(Sprite)
;detach parent
FindMapElement(*Sprite\CoucheParent\SpritesAttaches(), ""+Sprite)
DeleteMapElement(*Sprite\CoucheParent\SpritesAttaches())
;free resources
If *Sprite\Deformer : FreeMemory(*Sprite\Deformer) : EndIf
DeleteMapElement(MoteurSprite\Sprites(), ""+Sprite)
EndProcedure
Procedure.i CreerSpriteAnime(Sprite, Couche, x.f, y.f, Frame=#PB_Default, Couleur=#PB_Default, Transparence=#PB_Default, Angle.f=#PB_Default, EchelleX.f=#PB_Default, EchelleY.f=#PB_Default)
Protected Resultat
If Sprite=#PB_Any
Static NumeroSprite=$FFFF : NumeroSprite+103 : Sprite=NumeroSprite
AddMapElement(MoteurSprite\Sprites(), ""+Sprite)
Resultat=Sprite
Else
If SpriteID(Sprite) : LibererSprite(Sprite) : EndIf
Resultat=AddMapElement(MoteurSprite\Sprites(), ""+Sprite)
EndIf
With MoteurSprite\Sprites()
\Sprite=Sprite
\CoucheParent=CoucheID(Couche)
\CoucheParent\SpritesAttaches(""+Sprite)=MoteurSprite\Sprites()
Protected indexCoin, nouvelleCouleur=Couleur, nouvelleTransparence=Transparence, couleurDefaut
For indexCoin=0 To 3
couleurDefaut=MoteurSprite\SpriteDefaut\Couleurs[indexCoin]
If Couleur=#PB_Default : nouvelleCouleur=CouleurRGB(couleurDefaut) : EndIf
If Transparence=#PB_Default : nouvelleTransparence=Alpha(couleurDefaut) : EndIf
\Couleurs[indexCoin]=CouleurRGBA(nouvelleCouleur, nouvelleTransparence)
Next
If Frame=#PB_Default : \Frame=MoteurSprite\SpriteDefaut\Frame : Else : \Frame=Frame : EndIf
If x=#PB_Default : \x=MoteurSprite\SpriteDefaut\x : Else : \x=x : EndIf
If y=#PB_Default : \y=MoteurSprite\SpriteDefaut\y : Else : \y=y : EndIf
If Angle=#PB_Default : \Angle=MoteurSprite\SpriteDefaut\Angle : Else : \Angle=Angle : EndIf
If EchelleX=#PB_Default : \EchelleX=MoteurSprite\SpriteDefaut\EchelleX : Else : \EchelleX=EchelleX : EndIf
If EchelleY=#PB_Default : \EchelleY=MoteurSprite\SpriteDefaut\EchelleY : Else : \EchelleY=EchelleY : EndIf
ProcedureReturn Resultat
EndWith
EndProcedure
Procedure CacherSprite(Sprite, EstCache)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
*Sprite\Etat & ~#Sprite_Cache | Bool(EstCache)*#Sprite_Cache
EndProcedure
Procedure DesactiverSprite(Sprite, EstDesactive)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
*Sprite\Etat & ~#Sprite_Desactive | Bool(EstDesactive)*#Sprite_Desactive
EndProcedure
Procedure DeplacerSprite(Sprite, x.f, y.f, Mode=#PB_Relative)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
If Mode = #PB_Relative
*Sprite\x+x
*Sprite\y+y
Else
*Sprite\x=x
*Sprite\y=y
EndIf
EndProcedure
Procedure PivoterSprite(Sprite, Angle.f, Mode=#PB_Relative)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
If Mode=#PB_Relative
*Sprite\Angle+Angle
Else
*Sprite\Angle=Angle
EndIf
EndProcedure
Procedure EchelleSprite(Sprite, EchelleX.f, EchelleY.f, Mode=#PB_Absolute)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
If Mode=#PB_Absolute
*Sprite\EchelleX=EchelleX
*Sprite\EchelleY=EchelleY
Else
*Sprite\EchelleX+EchelleX
*Sprite\EchelleY+EchelleY
EndIf
EndProcedure
Procedure RetournerSprite(Sprite, RetournerX=#False, RetournerY=#False)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
With *Sprite
RetournerX & ~(#Sprite_RetournerX|#Sprite_RetournerY)
If RetournerX : \Etat | #Sprite_RetournerX : EndIf
If RetournerY : \Etat | #Sprite_RetournerY : EndIf
EndWith
EndProcedure
Procedure DeformerSprite(Sprite, x0.f, y0.f, x1.f, y1.f, x2.f, y2.f, x3.f, y3.f)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
With *Sprite\Deformer
*Sprite\Deformer=AllocateMemory(SizeOf(SP_DEFORMATION))
\x[0]=x0 : \y[0]=y0
\x[1]=x1 : \y[1]=y1
\x[2]=x2 : \y[2]=y2
\x[3]=x3 : \y[3]=y3
EndWith
EndProcedure
Procedure FausserSprite(Sprite, Premier.f, Second.f, Vertical=#False)
If Vertical
DeformerSprite(Sprite, 0, Premier, 0, Second, 0, Second, 0, Premier)
Else
DeformerSprite(Sprite, Premier, 0, Premier, 0, Second, 0, Second, 0)
EndIf
EndProcedure
Procedure AgencerSprite(Sprite, Gauche.f=#PB_Ignore, Haut.f=#PB_Ignore, Droite.f=#PB_Ignore, Bas.f=#PB_Ignore, EnPixels=#True)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
With *Sprite
Protected l=\CoucheParent\VueParent\LargeurCamera
Protected h=\CoucheParent\VueParent\CameraHauteur
Protected AgencementX, AgencementY
If Not EnPixels
If Haut<>#PB_Ignore : Haut*h : EndIf
If Bas<>#PB_Ignore : Bas*h : EndIf
If Droite<>#PB_Ignore : Droite*l : EndIf
If Gauche<>#PB_Ignore : Gauche*l : EndIf
EndIf
AgencementX+1*Bool(Gauche<>#PB_Ignore)+2*Bool(Droite<>#PB_Ignore)
AgencementY+1*Bool(Haut<>#PB_Ignore)+2*Bool(Bas<>#PB_Ignore)
Select AgencementX
Case 0 :
Case 1 :
Case 2 :
Case 3 :
EndSelect
EndWith
EndProcedure
Procedure DefinirTransparenceSprite(Sprite, Transparence, indexCoin=#PB_Any)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
If indexCoin=#PB_Any
For indexCoin=0 To 3
*Sprite\Couleurs[indexCoin]=CouleurRGBA(CouleurRGB(*Sprite\Couleurs[indexCoin]), Transparence)
Next
Else
*Sprite\Couleurs[indexCoin]=CouleurRGBA(CouleurRGB(*Sprite\Couleurs[indexCoin]), Transparence)
EndIf
EndProcedure
Procedure DefinirCouleurSprite(Sprite, Couleur, indexCoin=#PB_Any)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
If indexCoin=#PB_Any
For indexCoin=0 To 3
*Sprite\Couleurs[indexCoin]=CouleurRGBA(Couleur, Alpha(*Sprite\Couleurs[indexCoin]))
Next
Else
*Sprite\Couleurs[indexCoin]=CouleurRGBA(Couleur, Alpha(*Sprite\Couleurs[indexCoin]))
EndIf
EndProcedure
Procedure DefinirFrameSprite(Sprite, Frame)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
*Sprite\Frame=Frame
EndProcedure
Procedure.f AngleSprite(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\Angle
EndProcedure
Procedure.f SpriteX(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\x
EndProcedure
Procedure.f SpriteY(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\y
EndProcedure
Procedure.f SpriteEchelleX(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\EchelleX
EndProcedure
Procedure.f SpriteEchelleY(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\EchelleY
EndProcedure
Procedure.i couleurSprite(Sprite, indexCoin=0)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn CouleurRGB(*Sprite\Couleurs[indexCoin])
EndProcedure
Procedure.i TransparenceSprite(Sprite, indexCoin=0)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn Alpha(*Sprite\Couleurs[indexCoin])
EndProcedure
Procedure.i FrameSprite(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\Frame
EndProcedure
Procedure.i CacheSprite(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn Bool(*Sprite\Etat & #Sprite_Cache)
EndProcedure
Procedure.i EtatSprite(Sprite)
Protected *Sprite.SP_SPRITE=SpriteID(Sprite)
ProcedureReturn *Sprite\Etat
EndProcedure
;---------- Couche
Procedure LibererCouche(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
;delete dependencies
ForEach *Couche\SpritesAttaches()
FreeSprite(*Couche\SpritesAttaches()\Sprite)
Next
;detach parent
FindMapElement(*Couche\VueParent\AttachedCouches(), ""+Couche)
DeleteMapElement(*Couche\VueParent\AttachedCouches())
;free resources
FreeNode(*Couche\CouchePivot)
FreeNode(*Couche\CoucheDecalage)
FreeNode(*Couche\CouchePosition)
FreeNode(*Couche\CoucheOmbre)
FreeMesh(*Couche\Mesh)
FreeMesh(*Couche\OmbreMesh)
FreeMaterial(*Couche\Material)
FreeMaterial(*Couche\OmbreMateriel)
DeleteMapElement(MoteurSprite\Couches(), ""+Couche)
EndProcedure
Procedure.i CreerCouche(Couche, Vue, *AtlasID, MelangeMateriel=#PB_Default, FiltreMateriel=#PB_Default)
Protected Resultat
If Couche=#PB_Any
Static NumeroCouche=$FFFF : NumeroCouche+103 : Couche=NumeroCouche
AddMapElement(MoteurSprite\Couches(), ""+Couche)
Resultat=Couche
Else
If CoucheID(Couche) : LibererCouche(Couche) : EndIf
Resultat=AddMapElement(MoteurSprite\Couches(), ""+Couche)
EndIf
With MoteurSprite\Couches()
\Couche=Couche
\Atlas=*AtlasID
\Material=CreateMaterial(#PB_Any, TextureID(\Atlas\Texture))
MaterialCullingMode(\Material, #PB_Material_NoCulling)
If MelangeMateriel=#PB_Default : MelangeMateriel=MoteurSprite\CoucheDefaut\MelangeMateriel : EndIf
If FiltreMateriel=#PB_Default : FiltreMateriel=MoteurSprite\CoucheDefaut\FiltreMateriel : EndIf
MaterialFilteringMode(\Material, FiltreMateriel)
MaterialBlendingMode(\Material, MelangeMateriel)
DisableMaterialLighting(\Material, #True)
\OmbreMateriel=CopyMaterial(\Material, #PB_Any)
\Mesh=CreateMesh(#PB_Any, #PB_Mesh_TriangleList, #PB_Mesh_Dynamic)
SetMeshMaterial(\Mesh, MaterialID(\Material))
MeshVertexPosition(0, 0, 0)
MeshVertexNormal(0, 0, 0)
MeshVertexTangent(0, 0, 0)
MeshVertexTextureCoordinate(0, 0)
MeshVertexColor(RGBA(255, 255, 255, 255))
MeshVertexPosition(1, 0, 0)
MeshVertexPosition(1, 1, 0)
MeshFace(0, 1, 2)
FinishMesh(0)
NormalizeMesh(\Mesh)
\OmbreMesh=CreateMesh(#PB_Any, #PB_Mesh_TriangleList, #PB_Mesh_Dynamic)
SetMeshMaterial(\OmbreMesh, MaterialID(\OmbreMateriel))
MeshVertexPosition(0, 0, 0)
MeshVertexNormal(0, 0, 0)
MeshVertexTangent(0, 0, 0)
MeshVertexTextureCoordinate(0, 0)
MeshVertexColor(RGBA(255, 255, 255, 255))
MeshVertexPosition(1, 0, 0)
MeshVertexPosition(1, 1, 0)
MeshFace(0, 1, 2)
FinishMesh(0)
NormalizeMesh(\OmbreMesh)
\CoucheOmbre=CreateNode(#PB_Any)
\CouchePosition=CreateNode(#PB_Any)
\CoucheDecalage=CreateNode(#PB_Any)
\CouchePivot=CreateNode(#PB_Any)
SetRenderQueue(MeshID(\OmbreMesh), 1, 10)
SetRenderQueue(MeshID(\Mesh), 1, 100)
AttachNodeObject(\CouchePosition, NodeID(\CoucheOmbre))
AttachNodeObject(\CouchePosition, MeshID(\Mesh))
AttachNodeObject(\CoucheDecalage, NodeID(\CouchePosition))
AttachNodeObject(\CouchePivot, NodeID(\CoucheDecalage))
\VueParent=VueID(Vue)
\VueParent\AttachedCouches(""+Couche)=MoteurSprite\Couches()
AttachNodeObject(\VueParent\VuePivot, NodeID(\CouchePivot))
ScaleNode(\CoucheDecalage, \VueParent\EchelleX, \VueParent\EchelleY, 1)
MoveNode(\CoucheDecalage, \VueParent\DecalageX, \VueParent\DecalageY, 500)
ProcedureReturn Resultat
EndWith
EndProcedure
Procedure CacherCouche(Couche, EstCache)
Protected *Couche.SP_Couche=CoucheID(Couche)
With *Couche
If EstCache
If Not (\Etat & #Couche_Cache)
\Etat | #Couche_Cache
DetachNodeObject(\CouchePosition, MeshID(\Mesh))
If (\Etat & #Ombre_Couche) : DetachNodeObject(\CoucheOmbre, MeshID(\OmbreMesh)) : EndIf
EndIf
Else
If \Etat & #Couche_Cache
\Etat & ~#Couche_Cache
AttachNodeObject(\CouchePosition, MeshID(\Mesh))
If (\Etat & #Ombre_Couche) : AttachNodeObject(\CoucheOmbre, MeshID(\OmbreMesh)) : EndIf
EndIf
EndIf
EndWith
EndProcedure
Procedure DeplacerCouche(Couche, x.f, y.f, Mode=#PB_Relative)
Protected *Couche.SP_Couche=CoucheID(Couche)
If Mode = #PB_Relative
*Couche\x+x
*Couche\y+y
Else
*Couche\x=x
*Couche\y=y
EndIf
MoveNode(*Couche\CouchePosition, x, y, 0, Mode)
EndProcedure
Procedure PivoterCouche(Couche, Angle.f, Mode=#PB_Relative)
Protected *Couche.SP_Couche=CoucheID(Couche)
RotateNode(*Couche\CoucheRoll, 0, 0, Angle, Mode)
EndProcedure
Procedure EchelleCouche(Couche, EchelleX.f, EchelleY.f, Mode=#PB_Absolute)
Protected *Couche.SP_Couche=CoucheID(Couche)
If Mode=#PB_Absolute
*Couche\EchelleX=EchelleX
*Couche\EchelleY=EchelleY
Else
*Couche\EchelleX+EchelleX
*Couche\EchelleY+EchelleY
EndIf
ScaleNode(*Couche\CoucheEchelle, EchelleX, EchelleY, 1, Mode)
EndProcedure
Procedure DefinirOmbreCouche(Couche, CastOmbre, Couleur.f=#PB_Ignore, Transparence.f=#PB_Ignore, DecalageX.f=#PB_Ignore, DecalageY.f=#PB_Ignore)
Protected *Couche.SP_Couche=CoucheID(Couche)
With *Couche
If CastOmbre
If Not (\Etat & #Ombre_Couche)
\Etat | #Ombre_Couche
If Not (\Etat & #Couche_Cache)
AttachNodeObject(\CoucheOmbre, MeshID(\OmbreMesh))
EndIf
EndIf
If Couleur.f<>#PB_Ignore : \CouleurOmbre=CouleurRGBA(Couleur, Alpha(\CouleurOmbre)) : EndIf
If Transparence.f<>#PB_Ignore : \CouleurOmbre=CouleurRGBA(CouleurRGB(\CouleurOmbre), Transparence) : EndIf
If DecalageX.f<>#PB_Ignore : \DecalageOmbreX=DecalageX : EndIf
If DecalageY.f<>#PB_Ignore : \DecalageOmbreY=DecalageY : EndIf
MoveNode(\CoucheOmbre, \DecalageOmbreX, \DecalageOmbreY, 0, #PB_Absolute)
MaterialBlendingMode(\OmbreMateriel, #PB_Material_AlphaBlend)
Else
If \Etat & #Ombre_Couche
\Etat & ~#Ombre_Couche
DetachNodeObject(\CoucheOmbre, MeshID(\OmbreMesh))
EndIf
EndIf
EndWith
EndProcedure
Procedure DefinirOrdreCouche(Couche, Order, OrdreOmbre=#PB_Ignore)
Protected *Couche.SP_Couche=CoucheID(Couche)
With *Couche
If Order<>#PB_Ignore
If Order<0 : Order=0 : EndIf
If Order>10000 : Order=10000 : EndIf
SetRenderQueue(MeshID(\Mesh), 1, Order)
EndIf
If OrdreOmbre<>#PB_Ignore
If OrdreOmbre<0 : OrdreOmbre=0 : EndIf
If OrdreOmbre>10000 : OrdreOmbre=10000 : EndIf
SetRenderQueue(MeshID(\OmbreMesh), 1, OrdreOmbre)
EndIf
EndWith
EndProcedure
Procedure.f AngleCouche(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn NodeRoll(*Couche\CoucheRoll)
EndProcedure
Procedure.f CoucheX(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn *Couche\x
EndProcedure
Procedure.f CoucheY(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn *Couche\y
EndProcedure
Procedure.f CoucheEchelleX(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn *Couche\EchelleX
EndProcedure
Procedure.f CoucheEchelleY(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn *Couche\EchelleY
EndProcedure
Procedure.i CacheCouche(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn Bool(*Couche\Etat & #Couche_Cache)
EndProcedure
Procedure.i EtatCouche(Couche)
Protected *Couche.SP_Couche=CoucheID(Couche)
ProcedureReturn *Couche\Etat
EndProcedure
;---------- Vue
Procedure LibererVue(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
;delete dependencies
ForEach *Vue\AttachedCouches()
LibererCouche(*Vue\AttachedCouches()\Couche)
Next
;free resources
FreeCamera(*Vue\Camera)
FreeNode(*Vue\VuePivot)
DeleteMapElement(MoteurSprite\Vues(), ""+Vue)
EndProcedure
Procedure.i CreerVue(Vue, BackCouleur=0, EstEtire=#False, x.f=0, y.f=0, l.f=100, h.f=100)
Protected Resultat
If Vue=#PB_Any
Static NumeroVue=$FFFF : NumeroVue+103 : Vue=NumeroVue
AddMapElement(MoteurSprite\Vues(), ""+Vue)
Resultat=Vue
Else
If VueID(Vue) : LibererVue(Vue) : EndIf
Resultat=AddMapElement(MoteurSprite\Vues(), ""+Vue)
EndIf
With MoteurSprite\Vues()
\Vue=Vue
\Camera=CreateCamera(#PB_Any, x, y, l, h)
\CameraX=CameraViewX(\Camera)
\CameraY=CameraViewY(\Camera)
\LargeurCamera=CameraViewWidth(\Camera)
\CameraHauteur=CameraViewHeight(\Camera)
CameraBackColor(\Camera, BackCouleur)
CameraRange(\Camera, 0.1, 1000)
CameraProjectionMode(\Camera, #PB_Camera_Orthographic)
SetOrientation(CameraID(\Camera), 1, 0, 0, 0)
Protected Cache=CreateEntity(#PB_Any, MeshID(CreateCube(#PB_Any, 100)), #PB_Material_None)
ScaleEntity(Cache, 100, 100, 0.01)
HideEntity(Cache, 1)
MoveEntity(Cache, 0, 0, 500)
\VuePivot=CreateNode(#PB_Any)
\DecalageVue=CreateNode(#PB_Any)
\VuePosition=CreateNode(#PB_Any)
AttachNodeObject(\VuePosition, CameraID(\Camera))
AttachNodeObject(\DecalageVue, NodeID(\VuePosition))
AttachNodeObject(\VuePivot, NodeID(\DecalageVue))
AttachNodeObject(\VuePivot, EntityID(Cache))
RenderWorld()
If MousePick(\Camera, CameraViewX(\Camera), CameraViewY(\Camera))
\DecalageX=PickX()
\DecalageY=PickY()
If EstEtire
\EchelleX=Abs(PickX()/(ScreenWidth()/2))
\EchelleY=Abs(PickY()/(ScreenHeight()/2))
Else
\EchelleX=Abs(PickX()/(CameraViewWidth(\Camera)/2))
\EchelleY=Abs(PickY()/(CameraViewHeight(\Camera)/2))
EndIf
FreeEntity(Cache)
EndIf
ScaleNode(\DecalageVue, \EchelleX, \EchelleY, 1)
Static nouvelleVuePos : nouvelleVuePos+$FFFF
MoveNode(\VuePivot, nouvelleVuePos, nouvelleVuePos, nouvelleVuePos)
ProcedureReturn Resultat
EndWith
EndProcedure
Procedure ModeVueCamera(Vue, RenderMode=#PB_Camera_Textured)
Protected *Vue.SP_Vue=VueID(Vue)
CameraRenderMode(*Vue\Camera, RenderMode)
EndProcedure
Procedure DeplacerVue(Vue, x.f, y.f, Mode=#PB_Relative)
Protected *Vue.SP_Vue=VueID(Vue)
If Mode = #PB_Relative
*Vue\x+x
*Vue\y+y
Else
*Vue\x=x
*Vue\y=y
EndIf
ProcedureReturn MoveNode(*Vue\VuePosition, x, y, 0, Mode)
EndProcedure
Procedure PivoterVue(Vue, Angle.f, Mode=#PB_Relative)
Protected *Vue.SP_Vue=VueID(Vue)
RotateNode(*Vue\VueRoll, 0, 0, Angle, Mode)
EndProcedure
Procedure.f AngleVue(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn NodeRoll(*Vue\VueRoll)
EndProcedure
Procedure.f VueX(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\x
EndProcedure
Procedure.f VueY(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\y
EndProcedure
Procedure.i VueCameraX(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\CameraX
EndProcedure
Procedure.i VueCameraY(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\CameraY
EndProcedure
Procedure.i LargeurCameraVue(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\LargeurCamera
EndProcedure
Procedure.i HauteurCameraVue(Vue)
Protected *Vue.SP_Vue=VueID(Vue)
ProcedureReturn *Vue\CameraHauteur
EndProcedure
Procedure InitMoteurSprite()
If InitSprite()
With MoteurSprite
\SpriteDefaut=AddMapElement(\Sprites(), ""+#PB_Default)
\CoucheDefaut=AddMapElement(\Couches(), ""+#PB_Default)
\OrdreUV(0, 0)=0 : \OrdreUV(0, 1)=1 : \OrdreUV(0, 2)=2 : \OrdreUV(0, 3)=3 ;Normal
\OrdreUV(1, 0)=1 : \OrdreUV(1, 1)=0 : \OrdreUV(1, 2)=3 : \OrdreUV(1, 3)=2 ;Retourner X
\OrdreUV(2, 0)=3 : \OrdreUV(2, 1)=2 : \OrdreUV(2, 2)=1 : \OrdreUV(2, 3)=0 ;Retourner Y
\OrdreUV(3, 0)=2 : \OrdreUV(3, 1)=3 : \OrdreUV(3, 2)=0 : \OrdreUV(3, 3)=1 ;Retourner X & Y
EndWith
Protected CouleurOpaque=RGBA(255, 255, 255, 255)
Protected indexCoin
With MoteurSprite\SpriteDefaut
\EchelleX=1
\EchelleY=1
For indexCoin=0 To 3 : \Couleurs[indexCoin]=CouleurOpaque : Next
EndWith
With MoteurSprite\CoucheDefaut
\MelangeMateriel=#PB_Material_AlphaBlend
\FiltreMateriel=#PB_Material_Bilinear
EndWith
ProcedureReturn #True
EndIf
EndProcedure
Procedure RenduSprites()
Protected *Vue.SP_Vue, *Couche.SP_Couche, *Sprite.SP_SPRITE
Protected indexSommet
ForEach MoteurSprite\Vues()
ForEach MoteurSprite\Vues()\AttachedCouches()
*Couche=MoteurSprite\Vues()\AttachedCouches()
If *Couche\Etat & #Couche_Cache : Continue : EndIf
indexSommet=0
UpdateMesh(*Couche\Mesh, 0)
ForEach *Couche\SpritesAttaches()
*Sprite=*Couche\SpritesAttaches()
If *Sprite\Etat & #Sprite_Cache : Continue : EndIf
With *Sprite
Protected *Frame.SP_FRAME=\CoucheParent\Atlas\Frames(\Frame)
Protected x0.f, y0.f, x1.f, y1.f, hx.f, hy.f, i, RetournerMode=0
Dim x.f(3) : Dim y.f(3)
Dim u.f(3) : Dim v.f(3)
hx=*Frame\PointChaudX
hy=*Frame\PointChaudY
If Not (\Etat & #Sprite_RetournerXY)
CopyMemory(@*Frame\u[0], u(), 4*SizeOf(Float))
CopyMemory(@*Frame\v[0], v(), 4*SizeOf(Float))
Else
RetournerMode=1*Bool(\Etat & #Sprite_RetournerX)+2*Bool(\Etat & #Sprite_RetournerY)
If \Etat & #Sprite_RetournerX : hx=*Frame\Largeur-hx : EndIf
If \Etat & #Sprite_RetournerY : hy=*Frame\Hauteur-hy : EndIf
For i=0 To 3
u(i)=*Frame\u[MoteurSprite\OrdreUV(RetournerMode, i)]
v(i)=*Frame\v[MoteurSprite\OrdreUV(RetournerMode, i)]
Next
EndIf
If \Angle=0 And \Deformer=0
x0=\x-hx*\EchelleX : x1=x0+*Frame\Largeur*\EchelleX
y0=\y-hy*\EchelleY : y1=y0+*Frame\Hauteur*\EchelleY
x(0)=x0 : y(0)=y0 : x(1)=x1 : y(1)=y0
x(2)=x1 : y(2)=y1 : x(3)=x0 : y(3)=y1
Else
x0=-hx*\EchelleX : x1=x0+*Frame\Largeur*\EchelleX
y0=-hy*\EchelleY : y1=y0+*Frame\Hauteur*\EchelleY
x(0)=x0 : y(0)=y0 : x(1)=x1 : y(1)=y0
x(2)=x1 : y(2)=y1 : x(3)=x0 : y(3)=y1
If \Deformer
For i=0 To 3
x(i)+\Deformer\x[i]
y(i)+\Deformer\y[i]
Next
EndIf
Protected radian.f=Radian(\Angle)
Protected cos.f=Cos(radian), sin.f=Sin(radian)
For i=0 To 3
Protected px.f=x(i), py.f=y(i)
x(i)=\x+cos*px-sin*py
y(i)=\y+sin*px+cos*py
Next
EndIf
For i=0 To 3
MeshVertexPosition(x(i), y(i), 0)
MeshVertexTextureCoordinate(u(i), v(i))
MeshVertexColor(\Couleurs[i])
Next
MeshFace(indexSommet, indexSommet+1, indexSommet+2)
MeshFace(indexSommet+2, indexSommet+3, indexSommet)
indexSommet+4
EndWith
Next
FinishMesh(0)
With *Couche
If \Etat & #Ombre_Couche
Dim vertices.PB_meshvertex(0)
Dim faces.PB_MeshFace(0)
GetMeshData(\Mesh, 0, vertices(), #PB_Mesh_Vertex|#PB_Mesh_Vertex|#PB_Mesh_UVCoordinate, 0, MeshVertexCount(\Mesh, 0)-1)
GetMeshData(\Mesh, 0, faces(), #PB_Mesh_Face, 0, MeshIndexCount(\Mesh, 0)-1)
UpdateMesh(\OmbreMesh, 0)
For i=0 To ArraySize(vertices())
MeshVertexPosition(vertices(i)\x, vertices(i)\y, 0)
MeshVertexTextureCoordinate(vertices(i)\u, vertices(i)\v)
MeshVertexColor(\CouleurOmbre)
Next
For i=0 To ArraySize(faces())
MeshIndex(faces(i)\Index)
Next
FinishMesh(0)
EndIf
EndWith
Next
Next
EndProcedure
CompilerIf #PB_Compiler_IsMainFile
DisableExplicit
If InitEngine3D()=0 Or InitMoteurSprite()=0
MessageRequester("Init", "Echoué!")
End
EndIf
AntialiasingMode(#PB_AntialiasingMode_None)
win=OpenWindow(#PB_Any, 0, 0, 800, 600, "Moteur Sprite FX", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
OpenWindowedScreen(WindowID(win), 0, 0, WindowWidth(win), WindowHeight(win))
;dessiner image atlas
fontID=LoadFont(0, "Arial", 22, #PB_Font_Bold|#PB_Font_HighQuality|#PB_Font_Italic)
spriteAtlas=CreerAtlas(#PB_Any, 160, 128)
If StartDrawing(SortieAtlas(spriteAtlas))
DrawingMode(#PB_2DDrawing_Transparent|#PB_2DDrawing_AlphaBlend)
DrawingFont(fontID)
Texte.s = "MICOUTE"
DrawText(25, 10, Texte, RGBA(255, 255, 255, 255))
txtW=TextWidth(Texte)
txtH=TextHeight(Texte)
DrawingMode(#PB_2DDrawing_Gradient|#PB_2DDrawing_AlphaBlend)
BackColor(RGBA(255, 255, 0, 255))
GradientColor(0.8, RGBA(255, 0, 0, 50))
FrontColor(RGBA(200, 70, 10, 255))
LinearGradient(0, 0, 0, 64)
Box(5, 5, 16, 64)
ResetGradientColors()
BackColor(RGBA(0, 255, 0, 255))
GradientColor(0.8, RGBA(0, 0, 255, 50))
FrontColor(RGBA(60, 100, 255, 255))
LinearGradient(0, 0, 64, 0)
Box(21, 69, 64, 16)
ResetGradientColors()
BackColor(RGBA(255, 255, 255, 255))
GradientColor(0.6, RGBA(150, 150, 150, 255))
FrontColor(RGBA(255, 255, 255, 255))
LinearGradient(25, 53, 30, 70)
For i=0 To 6
RoundBox(25+i*20, 45, 16, 16, 7, 4)
Next
DrawingMode(#PB_2DDrawing_Outlined|#PB_2DDrawing_AlphaBlend)
FrontColor(RGBA(255, 255, 255, 255))
Box(5, 5, 16, 64)
Box(21, 69, 64, 16)
Box(0, 0, 159, 128)
StopDrawing()
EndIf
;extraire frames image
frameRouge=DefinirFrameAtlas(spriteAtlas, #PB_Any, 5, 5, 16, 64)
frameBleue=DefinirFrameAtlas(spriteAtlas, #PB_Any, 21, 69, 64, 16, 32, 8, #True)
frameTexte=DefinirFrameAtlas(spriteAtlas, #PB_Any, 25, 10, txtW, txtH)
;créer une vue d'arrière plan
vueFond=CreerVue(#PB_Any, RGB(10, 10, 10))
If vueFond
;créer couches FX
ajouterCoucheFX=CreerCouche(#PB_Any, vueFond, AtlasID(spriteAtlas), #PB_Material_Add, #PB_Material_None)
CouleurCoucheFX=CreerCouche(#PB_Any, vueFond, AtlasID(spriteAtlas), #PB_Material_Color, #PB_Material_None)
;créer sprites FX (changement de couleur du sprite par défaut)
DefinirCouleurSprite(#PB_Default, RGB(93, 137, 175), 2)
For i=1 To 10
ajouterFX=CreerSpriteAnime(#PB_Any, ajouterCoucheFX, 650, 200, frameRouge)
EchelleSprite(ajouterFX, 1, 1+i*0.1)
PivoterSprite(ajouterFX, -90+i*20)
Next
DefinirCouleurSprite(#PB_Default, RGB(93, 137, 175), 2)
For i=1 To 10
CouleurFX=CreerSpriteAnime(#PB_Any, CouleurCoucheFX, 650, 50, frameRouge)
EchelleSprite(CouleurFX, 1, 1+i*0.1)
PivoterSprite(CouleurFX, -90+i*20)
Next
DefinirCouleurSprite(#PB_Default, RGB(255, 255, 255))
EndIf
;créer vue premier plan
VuePP=CreerVue(#PB_Any, RGB(62, 62, 62), #False, 0, 0, 64.0, 85.34)
;Debug "Vue Caméra = "+VueCameraY(VuePP)+", "+VueCameraX(VuePP)+", "+LargeurCameraVue(VuePP)+", "+HauteurCameraVue(VuePP)
If VuePP
;créer des couches lissées et pixellisées
coucheLisse=CreerCouche(#PB_Any, VuePP, AtlasID(spriteAtlas))
pixelCouche=CreerCouche(#PB_Any, VuePP, AtlasID(spriteAtlas), #PB_Material_AlphaBlend, #PB_Material_None)
;réorganiser les couches et activer l'ombre
DefinirOmbreCouche(coucheLisse, #True, RGB(0, 0, 0), 100, 5, 5)
DefinirOrdreCouche(coucheLisse, 100, 90)
DefinirOrdreCouche(pixelCouche, 80)
;créer sprites
imageEntiere=CreerSpriteAnime(#PB_Any, pixelCouche, 5, 5, 0)
barreRouge=CreerSpriteAnime(#PB_Any, pixelCouche, 10, 150, frameRouge)
barreBleue=CreerSpriteAnime(#PB_Any, pixelCouche, 10+(16+8+1), 150+32, frameBleue)
;créer des sprites pivotés et mis à l'échelle
barreLisse=CreerSpriteAnime(#PB_Any, coucheLisse, 90, 190, frameBleue)
PivoterSprite(barreLisse, -10)
pixelBar=CreerSpriteAnime(#PB_Any, pixelCouche, 130, 190, frameBleue)
PivoterSprite(pixelBar, -10)
EchelleSprite(pixelBar, 2, 1)
;Debug "Angle Sprite = "+AngleSprite(pixelBar)+" Echelle X = "+SpriteEchelleX(pixelBar)+" Echelle Y = "+SpriteEchelleY(pixelBar)
;créer des sprites déformés
formeLisse=CreerSpriteAnime(#PB_Any, coucheLisse, 200, 150, frameRouge)
DeformerSprite(formeLisse, -16, 0, 16, 0, 8, 0, -8, 0)
pixelShape=CreerSpriteAnime(#PB_Any, pixelCouche, 224, 153, frameRouge)
FausserSprite(pixelShape, 32, 0)
;créer des sprites colorisés et retournés
txt=CreerSpriteAnime(#PB_Any, coucheLisse, 100+30, 300, frameTexte)
DefinirCouleurSprite(txt, RGB(255, 214, 126))
txtX=CreerSpriteAnime(#PB_Any, coucheLisse, 100+30, 300, frameTexte)
RetournerSprite(txtX, #True, #False)
DefinirTransparenceSprite(txtX, 150)
;Debug "Tranparence Sprite = "+TransparenceSprite(txtX)
txtY=CreerSpriteAnime(#PB_Any, coucheLisse, 100+30, 300, frameTexte)
RetournerSprite(txtY, #False, #True)
DefinirCouleurSprite(txtY, RGB(255, 14, 126), 0)
DefinirCouleurSprite(txtY, RGB(255, 14, 126), 2)
;Debug "Pos Sprite = "+SpriteX(txtY)+","+SpriteX(txtY)+" Couleur = "+Hex(couleurSprite(txtY, 2))
txtBoth=CreerSpriteAnime(#PB_Any, coucheLisse, 100+30, 300, frameTexte)
RetournerSprite(txtBoth, #True, #True)
DefinirTransparenceSprite(txtBoth, 50, 0)
DefinirTransparenceSprite(txtBoth, 50, 2)
;Debug "Sprite retouné X = "+Bool(EtatSprite(txtBoth)& #Sprite_RetournerX)+" retourné Y = "+Bool(EtatSprite(txtBoth)& #Sprite_RetournerY)
EndIf
Repeat
RenduSprites()
RenderWorld()
FlipBuffers()
Until WaitWindowEvent(1)=#PB_Event_CloseWindow
End
CompilerEndIf