http://bond357.free.fr/main/forums/viewtopic.php?id=10
je viens de le traduire pour PureBasic, c'est du vite fait, c'est un simple copier/coller.
J'espère que son auteur (qui fréquente ce forum) ne m'en voudra pas d'avoir repris ce code ?
Code : Tout sélectionner
;==================================================================
; Project Title : Simple Quadtree Demo
;
; Author : Seyhajin
;
; Email : seyhajin@hotmail.com
;
; Website : http://www.seyhajin.com
; http://bond357.free.fr/main/forums/viewtopic.php?id=10
;
; Version : 1.0
;
; Date : 12/03/2006
;
; Notes : Utilisation du Quadtree et du Frustum Culling, dans un univers 2D.
;
; Commandes :
; - Touches direct. : Bouge la camera
; - Mouse : Definit l'orientation de la camera
;
; References :
; - mon poto Google :o)
; - http://www.flipcode.com/articles/article_frustumculling.shtml
; - http://deptinfo.unice.fr/twiki/bin/view/Minfo03/AlgosJeux3DRapportFrustum
;
;==================================================================
; Definit le Frustum
Global p1.POINT, p2.POINT
Macro CosD(x)
Cos((x)*0.0174532)
EndMacro
Macro SinD(x)
Sin((x)*0.0174532)
EndMacro
; Enfants du Quadtree
Enumeration
#CHILD00
#CHILD01
#CHILD11
#CHILD10
EndEnumeration
; CAMERA
Structure CAMERA
x.l ; Position de la camera
y.l ; Position de la camera
fov.l ; Angle de vue
EndStructure
; QUADTREE
Structure QUADTREE
xmin.l ; Coordonnées du sommet haut gauche
ymin.l ; Coordonnées du sommet haut gauche
xmax.l ; Coordonnées du sommet bas droite
ymax.l ; Coordonnées du sommet bas droite
*Child.QUADTREE[4] ; Les 4 enfants du quadtree
EndStructure
; creation d'une camera
; creation d'une camera
Procedure Camera(x,y,fov)
*this.CAMERA = AllocateMemory(SizeOf(CAMERA))
*this\x = x : *this\y = y : *this\fov = fov
ProcedureReturn *this
EndProcedure
; Renvoie True si un point est dans le plan Left du Frustum
Procedure PointInFrustumL(*this.CAMERA,x,y)
If (-(x - *this\x) * (p1\y - *this\y) + (y - *this\y) * (p1\x - *this\x) >= 0)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
; Renvoie True si un point est dans le plan Right du Frustum
Procedure PointInFrustumR(*this.CAMERA,x,y)
If ( -(x - *this\x) * (p2\y - *this\y) + (y - *this\y) * (p2\x - *this\x) <= 0)
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
; Renvoie True si un point est dans le plan Front du Frustum (pas utilisé ici)
Procedure PointInFrustumF(*this.CAMERA,x,y)
ProcedureReturn ( -(x - *this\x) * (p3y - *this\y) + (y - *this\y) * (p3x - *this\x) >= 0)
EndProcedure
; Creation d'un quadtree de profondeur depth
; et associé à un carré de cotés xmax-xmin, ymax-ymin
Procedure Quadtree(xmin,ymin,xmax,ymax,depth)
*this.QUADTREE = AllocateMemory(SizeOf(QUADTREE))
*this\xmin = xmin
*this\xmax = xmax
*this\ymin = ymin
*this\ymax = ymax
If (depth > 0)
; On crée 4 enfants
xmoy = (xmin+xmax) / 2
ymoy = (ymin+ymax) / 2
depth = depth - 1
*this\Child[#CHILD00] = Quadtree(xmin,ymin,xmoy,ymoy,depth) ; Haut gauche
*this\Child[#CHILD01] = Quadtree(xmin,ymoy,xmoy,ymax,depth) ; Bas gauche
*this\Child[#CHILD11] = Quadtree(xmoy,ymoy,xmax,ymax,depth) ; Bas droite
*this\Child[#CHILD10] = Quadtree(xmoy,ymin,xmax,ymoy,depth) ; Haut droite
EndIf
ProcedureReturn *this
EndProcedure
; On teste si un des 4 sommets du carré associé au quadtree
; est visible par la camera
Procedure QuadInFrustum(*this.QUADTREE,*cam.CAMERA)
Define nbPlansInterieur
; Plan de gauche
nbPlansInterieur = 0
nbPlansInterieur = nbPlansInterieur + PointInFrustumL(*cam,*this\xmin,*this\ymin)
nbPlansInterieur = nbPlansInterieur + PointInFrustumL(*cam,*this\xmin,*this\ymax)
nbPlansInterieur = nbPlansInterieur + PointInFrustumL(*cam,*this\xmax,*this\ymin)
nbPlansInterieur = nbPlansInterieur + PointInFrustumL(*cam,*this\xmax,*this\ymax)
If nbPlansInterieur = 0 : ProcedureReturn #False : EndIf
; Plan de droite
nbPlansInterieur = 0
nbPlansInterieur = nbPlansInterieur + PointInFrustumR(*cam,*this\xmin,*this\ymin)
nbPlansInterieur = nbPlansInterieur + PointInFrustumR(*cam,*this\xmin,*this\ymax)
nbPlansInterieur = nbPlansInterieur + PointInFrustumR(*cam,*this\xmax,*this\ymin)
nbPlansInterieur = nbPlansInterieur + PointInFrustumR(*cam,*this\xmax,*this\ymax)
If nbPlansInterieur = 0 : ProcedureReturn #False : EndIf
ProcedureReturn #True
EndProcedure
; Rendu du Quadtree
Procedure RenderQuadtree(*this.QUADTREE,*cam.CAMERA,depth)
If QuadInFrustum(*this,*cam)
If (depth > 1)
FrontColor(#Gray)
LineXY((*this\xmin+*this\xmax)/2,*this\ymin,(*this\xmin+*this\xmax)/2,*this\ymax)
LineXY(*this\xmin,(*this\ymin+*this\ymax)/2,*this\xmax,(*this\ymin+*this\ymax)/2)
depth = depth - 1
RenderQuadtree(*this\Child[#CHILD00],*cam,depth)
RenderQuadtree(*this\Child[#CHILD01],*cam,depth)
RenderQuadtree(*this\Child[#CHILD11],*cam,depth)
RenderQuadtree(*this\Child[#CHILD10],*cam,depth)
Else
FrontColor(RGB(196,196,196))
Box(*this\xmin+1,*this\ymin+1,*this\xmax-*this\xmin-1,*this\ymax-*this\ymin-1)
EndIf
EndIf
EndProcedure
Procedure.f Atan2(y.f,x.f)
!fld dword[p.v_y]
!fld dword[p.v_x]
!fpatan
ProcedureReturn
EndProcedure
;==============================================================================================
; EXAMPLE
;==============================================================================================
InitSprite()
InitMouse()
InitKeyboard()
OpenScreen(800,600,32,"Simple Quadtree Demo - Seyhajin")
; Variables de configuration
QuadDepth = 6 ; Profondeur du quadtree (nb de fois qu'on decoupe le plan)
QuadSize = 599 ; Taille initiale du quadtree
CamSpeed.f = 2 ; Vitesse de deplacement de la camera
CamFOV.f = 60.0 / 2.0 ; Angle de vue de la camera (default = 90)
ViewLine = 200 ; Taille de la ligne des plans
; Creation de la camera
*cam.CAMERA=camera(QuadSize/2,QuadSize/2,CamFOV)
; Creation du Quadtree principale
*root.QUADTREE=Quadtree(0,0,QuadSize,QuadSize,QuadDepth)
;----------------------------------
; BOUCLE PRINCIPALE
;----------------------------------
Repeat
ClearScreen(#Black)
; Update Camera position
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Up)
*cam\y = *cam\y - CamSpeed
ElseIf KeyboardPushed(#PB_Key_Down)
*cam\y = *cam\y + CamSpeed
EndIf
If KeyboardPushed(#PB_Key_Left)
*cam\x = *cam\x - CamSpeed
ElseIf KeyboardPushed(#PB_Key_Right)
*cam\x = *cam\x + CamSpeed
EndIf
If ExamineMouse()
x.f = MouseX() - *cam\x
y.f = MouseY() - *cam\y
angle.f = 180+(ATan2(-y,-x)*57.295779)
EndIf
; Rendu du quadtree
StartDrawing(ScreenOutput())
Box(*root\xmin,*root\ymin,*root\xmax,*root\ymax,#White)
RenderQuadtree(*root,*cam,QuadDepth)
; Dessine la pyramide de vue (Frustum)
LineXY(*cam\x,*cam\y,*cam\x+(ViewLine/2)*CosD(angle),*cam\y+(ViewLine/2)*SinD(angle),#Yellow)
; Plan gauche
p1\x = *cam\x+ViewLine*CosD(angle-CamFOV)
p1\y = *cam\y+ViewLine*SinD(angle-CamFOV)
LineXY(*cam\x,*cam\y,p1\x,p1\y,#Red)
; Plan droit
p2\x = *cam\x+ViewLine*CosD(angle+CamFOV)
p2\y = *cam\y+ViewLine*SinD(angle+CamFOV)
LineXY(*cam\x,*cam\y,p2\x,p2\y,#Red)
; Dessine la camera
Circle(*cam\x,*cam\y,6,#Blue)
StopDrawing()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)