Page 1 sur 3

Dessiner un triangle rempli

Publié : mer. 25/août/2004 20:58
par Dr. Dri

Code : Tout sélectionner

Procedure Swap(*a.l, *b.l, size.l)
  If *a=0 Or *b=0 Or size<1
    ProcedureReturn 0
  EndIf

  *c.l = AllocateMemory(size)
  If *c=0 : ProcedureReturn 0 : EndIf
 
  CopyMemory(*a, *c, size)
  CopyMemory(*b, *a, size)
  CopyMemory(*c, *b, size)
 
  FreeMemory(*c)

  ProcedureReturn 1
EndProcedure

Procedure Sgn(x)
  If x>0
    ProcedureReturn 1
  ElseIf x<0
    ProcedureReturn -1
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

Procedure FilledTriangle(x1, y1, x2, y2, x3, y3, couleur)

  If y1>y2
    Swap(@x1, @x2, 4)
    Swap(@y1, @y2, 4)
  EndIf
  If y1>y3
    Swap(@x1, @x3, 4)
    Swap(@y1, @y3, 4)
  EndIf
  If y2>y3
    Swap(@x2, @x3, 4)
    Swap(@y2, @y3, 4)
  EndIf
  
  dx1 = x3-x1 : dy1 = y3-y1 : sgn1 = Sgn(dx1)
  dx2 = x2-x1 : dy2 = y2-y1 : sgn2 = Sgn(dx2)
  dx3 = x3-x2 : dy3 = y3-y2 : sgn3 = Sgn(dx3)
  dx1 = Abs(dx1)
  dx2 = Abs(dx2)
  dx3 = Abs(dx3)
  
  err1 = 0
  err2 = 0
  err3 = 0
  
  xl = x1
  xr = x1
  
  If y1<>y2
    For y=y1 To y2
      If y>=0
      
        LineXY(xl, y, xr, y, couleur)
        
        err1 + dx1
        While err1>dy1
          xl + sgn1
          err1 - dy1
        Wend
        
        err2 + dx2
        While err2>dy2
          xr + sgn2
          err2 - dy2
        Wend
      
      EndIf
    Next y
  EndIf
  
  If y1<>y2
    For y=y2 To y3
      If y>=0
      
        LineXY(xl, y, xr, y, couleur)
        
        err1 + dx1
        While err1>dy1
          xl + sgn1
          err1 - dy1
        Wend
        
        err3 + dx3
        While err3>dy3
          xr + sgn3
          err3 - dy3
        Wend
      
      EndIf
    Next y
  EndIf
  
EndProcedure

;- Debut du programme
OpenWindow(1, 100, 100, 300, 200, #PB_Window_MinimizeGadget, "")

max=40
dessine = 0

If StartDrawing(WindowOutput())
  Box(0, 0, 300, 200, RGB(255, 255, 255))
  StopDrawing()
EndIf

Repeat
  
  x1 = Random(299)
  y1 = Random(199)
  x2 = Random(299)
  y2 = Random(199)
  x3 = Random(299)
  y3 = Random(199)
  
  r = Random(255)
  g = Random(255)
  b = Random(255)
  
  If dessine<max
    If StartDrawing(WindowOutput())
      FilledTriangle(x1, y1, x2, y2, x3, y3, RGB(r, g, b))
      StopDrawing()
    EndIf
    dessine+1
  EndIf
  
  event = WindowEvent()
Until event=#PB_Event_CloseWindow
Dri

Publié : jeu. 26/août/2004 15:42
par Le Soldat Inconnu
un truc tout bête

simplement dessiner les lignes entres chaque points puis faire un remplissage au centre du triangle, non ?

je vais faire un exemple

Publié : jeu. 26/août/2004 15:46
par Backup
@Dri: c'est tres rapide !! :D
mais t'a vraiment pas trouvé plus simple ?? 8O

c'est pas Dri qu'il fallai prendre comme pseudo , c'est pierre de Rosette !! :D
je comprend jamais rien a tes codes !! :lol: :lol:

Publié : jeu. 26/août/2004 15:50
par Chris
Dobro a écrit :@Dri: c'est tres rapide !! :D
mais t'a vraiment pas trouvé plus simple ?? 8O

c'est pas Dri qu'il fallai prendre comme pseudo , c'est pierre de Rosette !! :D
je comprend jamais rien a tes codes !! :lol: :lol:
T'est pas le seul. :lol:
J'ai beau chercher les commentaires, je trouve rien :wink:

Publié : jeu. 26/août/2004 22:49
par Dr. Dri
ah euh oué c'est pas commenté
j'ai pas mal galéré pour le faire (ca risque de me servir)

le but est de se baser sur l'algo de tracés de ligne de bresenham
(jvais pas vous faire un court là dessus ^^ je capte pas à 100%)

donc le principe c'est de trier les points du plus haut au plus bas
(la partie avec les swap)

ensuite on trace le triangle avec des lignes horizontales en partant de haut en bas

avec un triangle quelconque ca donne à peu pres ca :

Code : Tout sélectionner

         A




                   B



C
donc on part du y de A à celui de B
en tracant des lignes horizonatles (on calcule x gauche et droite, c'est bresenham)
ensuite une fois arrivé à B on poursuit jusqu'au y de C

voila pour les grandes lignes

Sinon pour ce qui est d'utiliser la fonction fill
c'est toujours risqué... étant donné qu'il y a tout de même d'autres points de diverses couleurs là où le triangle est censé arriver... j'ai pas trouvé moins compliqué (ou plus simple de mon point de vue ^^) pour etre certain que le triangle soit tracé completement...

Dri

Publié : lun. 30/août/2004 8:05
par Psycode
...

Publié : lun. 30/août/2004 8:55
par Dr. Dri
le résultat est joli ^^
la mienne n'utilise pas de réel 8)

Dri

Publié : lun. 30/août/2004 9:12
par Psycode
Héhéhé :lol:

Dri, faisons un concours. Lancons nous un chalenge et voyons qui fait le code le plus optimisé ! :wink:

Publié : lun. 30/août/2004 10:44
par Dr. Dri
lol
l'optimisation c'est pas mon truc ^^
déjà j'ai pondu ca avec du mal ^^

Dri

PS. je ferais au moins des tests de vitesse pour comparer nos codes si t'en pond un avec un triangle uni et sans bordure (comme le mien)

Routine de tracage de triangles pleins

Publié : lun. 30/août/2004 11:04
par Psycode
...

Publié : lun. 30/août/2004 21:15
par crisot
Je vous fourni la mienne, pour ceux qui en ont besoin. La première version est semie optimisée, mais surtout, très compacte, claire et lisible. Facile à adapter et à passer en procédure. Il suffit de rempli les tableaux X() et Y() avec les points qu'on veux.


Code : Tout sélectionner

#Window = 0 
#Width = 640
#Height = 480 
#Timer = 0 

;* Initialisation de DirectX *;
If InitSprite() = 0 Or InitKeyboard() = 0 
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0) 
  CloseWindow(#Window) : End 
EndIf 

;* Ouverture de la fenêtre et de l'écran *;
hwnd = OpenWindow(#Window, 0, 0, #Width, #Height, #PB_Window_TitleBar | #PB_Window_ScreenCentered, "") 
OpenWindowedScreen(hwnd, 0, 0, #Width, #Height, 0, 0, 0) 

ClearScreen(0, 0, 0) 




;*********************************************;

;* 3 pixels au pif *;

Dim X(2) : Dim Y(2)
For i=0 To 2: X(i)=Random(#Width-1) : Y(i)=Random(#Height-1) : Next

;* On tri les points (cette partie n'est pas optimale, mais ça suffira bien) *;

T=65535 : B=0 : BI=0
For i=0 To 2 : Y=Y(i) : If Y<T : T=Y : BI=i : EndIf : If Y>B : B=Y : EndIf : Next

XA.f=X(BI) : Y1=Y(BI) : BI=BI+1 : If BI=3 : BI=0 : EndIf
X2.f=X(BI) : Y2=Y(BI) : BI=BI+1 : If BI=3 : BI=0 : EndIf
X3.f=X(BI) : Y3=Y(BI) : XB.f=XA

;* On trace *;

PA1.f = (X2-XA)/((Y2-Y1)) : PB1.f = (X3-XA)/((Y3-Y1)) : PC.f = (X3-X2)/((Y3-Y2))

If Y2<Y3 : HALF=Y2 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y3: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y1=Y2 : XA = X2: EndIf           ;* cas particulier à ne pas oublier *;
If Y1=Y3 : XB = X3: EndIf           ;* cas particulier à ne pas oublier *;

StartDrawing(ScreenOutput()) 
For i=T To HALF-1 : LineXY(XA, i, XB, i, 16777215) 
XA=XA+PA1 : XB=XB+PB1 : Next
For i=HALF To B : LineXY(XA, i, XB, i, 16777215) 
XA=XA+PA2 : XB=XB+PB2 : Next 
StopDrawing()

FlipBuffers() 

;*********************************************;






;* On quite ! *;

;End
Repeat  
  ExamineKeyboard() 
  While WindowEvent() : Wend 
  If KeyboardPushed(#PB_Key_Escape) : quit = 1 : EndIf 
Until quit = 1 
End


Et voici la deuxième version, qui est en fait la meme, mais optimisée, sans les DIM que PB ne semble pas trop apprécier. Elle est plus longue mais nettement plus rapide, et encore un peu optimisable, mais j'ai préféré ne pas aller plus loin sinon après ça ne ressemble plus à rien

Code : Tout sélectionner

#Window = 0 
#Width = 640
#Height = 480 
#Timer = 0 

;* Initialisation de DirectX *;
If InitSprite() = 0 Or InitKeyboard() = 0 
  MessageRequester("Erreur", "Impossible d'initialiser DirectX", 0) 
  CloseWindow(#Window) : End 
EndIf 

;* Ouverture de la fenêtre et de l'écran *;
hwnd = OpenWindow(#Window, 0, 0, #Width, #Height, #PB_Window_TitleBar | #PB_Window_ScreenCentered, "") 
OpenWindowedScreen(hwnd, 0, 0, #Width, #Height, 0, 0, 0) 

ClearScreen(0, 0, 0) 

StartDrawing(ScreenOutput()) 






;********************************;

;* 3 pixels au pif *;

X0=Random(#Width-1)
Y0=Random(#Height-1)
X1=Random(#Width-1)
Y1=Random(#Height-1)
X2=Random(#Width-1)
Y2=Random(#Height-1)

;* Recherche du point le plus haut et le plus bat *;

T=Y0 : B=Y0 : CAS=0
If Y1<T : T=Y1 : CAS=1 : EndIf : If Y1>B : B=Y1 : EndIf
If Y2<T : T=Y2 : CAS=2 : EndIf : If Y2>B : B=Y2 : EndIf

;* Calcul des pentes dans les 3 cas possibles *;

If CAS=0
XA.f=X0 : XB.f=X0
PA1.f = (X1-X0)/(Y1-Y0) : PB1.f = (X2-X0)/(Y2-Y0) : PC.f = (X2-X1)/(Y2-Y1)
If Y1<Y2 : HALF=Y1 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y2: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y0=Y1 : XA = X1: EndIf           ;* cas particulier à ne pas oublier *;
If Y0=Y2 : XB = X2: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

If CAS=1
XA.f=X1 : XB.f=X1
PA1.f = (X2-X1)/(Y2-Y1) : PB1.f = (X0-X1)/(Y0-Y1) : PC.f = (X0-X2)/(Y0-Y2)
If Y2<Y0 : HALF=Y2 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y0: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y1=Y2 : XA = X2: EndIf           ;* cas particulier à ne pas oublier *;
If Y1=Y0 : XB = X0: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

If CAS=2
XA.f=X2 : XB.f=X2
PA1.f = (X0-X2)/(Y0-Y2) : PB1.f = (X1-X2)/(Y1-Y2) : PC.f = (X1-X0)/(Y1-Y0)
If Y0<Y1 : HALF=Y0 : PA2.f=PC : PB2.f=PB1 : Else : HALF=Y1: PA2.f=PA1 : PB2.f=PC :  EndIf
If Y2=Y0 : XA = X0: EndIf           ;* cas particulier à ne pas oublier *;
If Y2=Y1 : XB = X1: EndIf           ;* cas particulier à ne pas oublier *;
EndIf

;* Traçage *;

For i=T To HALF-1 : LineXY(XA, i, XB, i, 16777215)
XA=XA+PA1 : XB=XB+PB1 : Next
For i=HALF To B : LineXY(XA, i, XB, i, 16777215)
XA=XA+PA2 : XB=XB+PB2 : Next 

;********************************;






;* On quite ! *;

StopDrawing()
FlipBuffers() 

Repeat  
  ExamineKeyboard() 
  While WindowEvent() : Wend 
  If KeyboardPushed(#PB_Key_Escape) : quit = 1 : EndIf 
Until quit = 1 
End


En fait j'ai fais ça en 20 minutes suite à une mise au défit par Psycode... A vous de juger ;) C'est mon premier programme en PB qu'hier soir encore je ne connaissais pas, habituellement je programme pas en basic, mais en tout cas celui ci est prometeur ;)

Publié : lun. 30/août/2004 23:32
par Backup
ça va surement etre le mien le plus court et le plus rapide :D
et le plus convivial car on peut choisir l'angle de l'orientation du triangle,l'ouverture en degres du sommet,et l'emplacement dans l'ecran ainsi que la couleur de la ligne de pourtour
et tout ça grace au sinus et cosinus !!
j'y ai passé l'apres-midi mais voila !

par contre j'ai pas chercher a la remplir !! mais un bon fill area bien plaçé !! :D


...............
:lol: :lol:

Publié : lun. 30/août/2004 23:50
par crisot
tu triche, tu fais un linexy d'un point à un autre :) La question était le remplissage ici, et un fill area n'overwritte pas les pixels isolés :)

Publié : mar. 31/août/2004 8:25
par Backup
bah !! la routine est interressante quand meme non ? :D

apres tout ça reste un triangle !! :lol: :lol: plein de vide !! :lol:

Publié : mer. 01/sept./2004 13:28
par Psycode
...