LineXY & Couleurs A&B

Partagez votre expérience de PureBasic avec les autres utilisateurs.
Anonyme

LineXY & Couleurs A&B

Message par Anonyme »

Voici une routine que j'ai chopé sur gougle, et filé à tmyke pour la traduction c++ -> pb
le tracage marche bien, mais je n'arrive pas à faire un "dégradé" de couleur... pourtant cela n'a pas l'air compliqué :?
je part de la couleur A pour aller jusqu'a la couleur B
en tenant compte de la distance entre les 2 points...
j'ai besoin d'un regard neuf :p


merki

Code : Tout sélectionner

Global SCREEN_W=640
Global SCREEN_H=480

Procedure.l Signe(a.l)
  If a>0
    ProcedureReturn 1
  ElseIf a=0
    ProcedureReturn 0
  Else
    ProcedureReturn -1
  EndIf
EndProcedure

Procedure.l Max(a.l, b.l)
  If a>b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
  
EndProcedure

Procedure Distance(x1,y1,z1,x2,y2,z2)
  Protected Result.f
  Result = Sqr(  (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2) )
  ProcedureReturn Result
EndProcedure


Procedure DrawLinePtr3D(x1.l, y1.l, z1.l,  x2.l,  y2.l,  z2.l,CouleurStart.l,CouleurEnd.l,Dist=15)
  
  Protected  xd.l, yd.l, zd.l
  Protected x.l, y.l, z.l
  Protected ax.l, ay.l, az.l
  Protected sx.l, sy.l, sz.l
  Protected dx.l, dy.l, dz.l
  Protected Couleur.l,Pas.l,Distance.l
  
  Couleur = CouleurStart
  Distance = Distance(x1,y1,z1,x2,y2,z2)
  Pas = (CouleurEnd-CouleurStart)/Distance
   
  If x1<>0 And y1<>0 And x2<>0 And y2<>0
    
    dx = x2 - x1
    dy = y2 - y1
    dz = z2 - z1
    
    ax = Abs(dx) *2
    ay = Abs(dy) *2
    az = Abs(dz) *2   ;ou     az = Abs(dz)  :   az = az << 1
    
    
    sx = Signe(dx)
    sy = Signe(dy)
    sz = Signe(dz)
    
    x = x1
    y = y1
    z = z1
    
    If (ax >= Max(ay, az))            ; x dominant
      
      yd = ay - (ax >> 1)
      zd = az - (ax >> 1)
      Repeat
        
        Couleur+Pas
        
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
          ;PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf 
        
        
        If (x = x2)
          ProcedureReturn;
        EndIf
        
        If (yd >= 0)
          y + sy        ; y +1 Or 0 Or -1
          yd - ax;
        EndIf
        
        If (zd >= 0)
          z + sz;      ; z +1 or 0 or -1
          zd - ax;
        EndIf
        
        x + sx             ; x +1 Or 0 Or -1
        yd + ay;
        zd + az;
      Until 0
      
    ElseIf (ay >= Max(ax, az))            ;  y dominant */
      
      xd = ax - (ay >> 1)
      zd = az - (ay >> 1)
      Repeat
        
        Couleur+Pas
        
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
          ;PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf 
        
        If (y = y2)
          ProcedureReturn;
        EndIf
        
        If (xd >= 0)
          x + sx       ;x +1 Or 0 Or -1
          xd - ay
        EndIf
        
        If (zd >= 0)
          z + sz       ;z +1 Or 0 Or -1
          zd - ay
        EndIf
        
        y + sy                 ;y +1 Or 0 Or -1
        xd + ax
        zd + az
      Until 0
      
    ElseIf (az >= Max(ax, ay))            ; z dominant */
      
      xd = ax - (az >> 1)
      yd = ay - (az >> 1)
      Repeat
        
        Couleur+Pas
        
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
         ; PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf 
        
        If (z = z2)
          ProcedureReturn;
        EndIf
        
        If (xd >= 0)
          x + sx    ;/x +1 or 0 or -1
          xd - az
        EndIf
        
        If (yd >= 0)
          y + sy     ;y +1 Or 0 Or -1
          yd - az
        EndIf
        
        z + sz                ;z +1 Or 0 Or -1
        xd + ax
        yd + ay
      Until 0
    EndIf
  EndIf  
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or InitSound() = 0
  End
EndIf

OpenScreen(640,480,32,"")




Repeat
  ExamineKeyboard() : ExamineMouse()
  ClearScreen(0)
  
  StartDrawing(ScreenOutput())
    DrawLinePtr3D(100,100,100,250,100,100,RGB(255,255,255),RGB(255,0,0))
  StopDrawing()
  
  
  FlipBuffers(2) 
Until KeyboardPushed(#PB_Key_Escape)
tmyke
Messages : 1554
Inscription : lun. 24/juil./2006 6:44
Localisation : vosges (France) 47°54'39.06"N 6°20'06.39"E

Message par tmyke »

En fait, le soucis vient de la division qui ne donne pas les bons composants séparés.
En séparant tout, cela semble pas trop mal fonctionner, meme si le code est plus lourd
(y-a surement moyen d'améliorer)

Code : Tout sélectionner

Global SCREEN_W=640
Global SCREEN_H=480

Procedure.l Signe(a.l)
  If a>0
    ProcedureReturn 1
  ElseIf a=0
    ProcedureReturn 0
  Else
    ProcedureReturn -1
  EndIf
EndProcedure

Procedure.l Max(a.l, b.l)
  If a>b
    ProcedureReturn a
  Else
    ProcedureReturn b
  EndIf
 
EndProcedure

Procedure Distance(x1,y1,z1,x2,y2,z2)
  Protected Result.f
  Result = Sqr(  (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2) )
  ProcedureReturn Result
EndProcedure


Procedure DrawLinePtr3D(x1.l, y1.l, z1.l,  x2.l,  y2.l,  z2.l,CouleurStart.l,CouleurEnd.l,Dist=15)
 
  Protected  xd.l, yd.l, zd.l
  Protected x.l, y.l, z.l
  Protected ax.l, ay.l, az.l
  Protected sx.l, sy.l, sz.l
  Protected dx.l, dy.l, dz.l
  Protected Couleur.l,Pas.l,Distance.l
 
  Couleur = CouleurStart
  Distance = Distance(x1,y1,z1,x2,y2,z2)
   
REDStart = CouleurStart & $ff 
GREENStart = CouleurStart & $ff00 : GREENStart >> 8
BLUEStart = CouleurStart & $ff0000 : BLUEStart >> 16
 
REDEnd = CouleurEnd & $ff 
GREENEnd = CouleurEnd & $ff00 : GREENEnd >> 8
BLUEEnd = CouleurEnd & $ff0000 : BLUEEnd >> 16
 
PasRed = (REDStart - REDEnd) /Distance
PasGreen = (GREENStart - GREENEnd) /Distance
PasBlue = (BLUEStart - BLUEEnd) /Distance

 
   
  If x1<>0 And y1<>0 And x2<>0 And y2<>0
   
    dx = x2 - x1
    dy = y2 - y1
    dz = z2 - z1
   
    ax = Abs(dx) *2
    ay = Abs(dy) *2
    az = Abs(dz) *2   ;ou     az = Abs(dz)  :   az = az << 1
   
   
    sx = Signe(dx)
    sy = Signe(dy)
    sz = Signe(dz)
   
    x = x1
    y = y1
    z = z1
   
    If (ax >= Max(ay, az))            ; x dominant
     
      yd = ay - (ax >> 1)
      zd = az - (ax >> 1)
      Repeat
       
        ;Couleur+Pas
        REDStart + PasRed
        GREENStart + PasGreen
        BLUEStart + PasBlue
        Couleur = RGB(REDStart, GREENStart, BLUEStart) 
       
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
          ;PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf
       
       
        If (x = x2)
          ProcedureReturn;
        EndIf
       
        If (yd >= 0)
          y + sy        ; y +1 Or 0 Or -1
          yd - ax;
        EndIf
       
        If (zd >= 0)
          z + sz;      ; z +1 or 0 or -1
          zd - ax;
        EndIf
       
        x + sx             ; x +1 Or 0 Or -1
        yd + ay;
        zd + az;
      Until 0
     
    ElseIf (ay >= Max(ax, az))            ;  y dominant */
     
      xd = ax - (ay >> 1)
      zd = az - (ay >> 1)
      Repeat
       
        REDStart + PasRed
        GREENStart + PasGreen
        BLUEStart + PasBlue
        Couleur = RGB(REDStart, GREENStart, BLUEStart) 
       
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
          ;PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf
       
        If (y = y2)
          ProcedureReturn;
        EndIf
       
        If (xd >= 0)
          x + sx       ;x +1 Or 0 Or -1
          xd - ay
        EndIf
       
        If (zd >= 0)
          z + sz       ;z +1 Or 0 Or -1
          zd - ay
        EndIf
       
        y + sy                 ;y +1 Or 0 Or -1
        xd + ax
        zd + az
      Until 0
     
    ElseIf (az >= Max(ax, ay))            ; z dominant */
     
      xd = ax - (az >> 1)
      yd = ay - (az >> 1)
      Repeat
       
        REDStart + PasRed
        GREENStart + PasGreen
        BLUEStart + PasBlue
        Couleur = RGB(REDStart, GREENStart, BLUEStart) 
       
        If x>0 And x<SCREEN_W-1 And y>0 And y<SCREEN_H-1 And z>Dist
         ; PokeL(*DrawingBuffer + (x*PixFrt) + SCREEN_W * (y*PixFrt),Couleur)
          Plot(x,y,Couleur)
        EndIf
       
        If (z = z2)
          ProcedureReturn;
        EndIf
       
        If (xd >= 0)
          x + sx    ;/x +1 or 0 or -1
          xd - az
        EndIf
       
        If (yd >= 0)
          y + sy     ;y +1 Or 0 Or -1
          yd - az
        EndIf
       
        z + sz       ;z +1 Or 0 Or -1
        xd + ax
        yd + ay
      Until 0
    EndIf
  EndIf 
EndProcedure


If InitSprite() = 0 Or InitKeyboard() = 0 Or InitMouse() = 0 Or InitSound() = 0
  End
EndIf

OpenScreen(640,480,32,"")



Repeat
  ExamineKeyboard() : ExamineMouse()
  ClearScreen(0)
 
  StartDrawing(ScreenOutput())
    DrawLinePtr3D(100,100,100,250,100,100,RGB(255,0,0),RGB(0,0,255))
  StopDrawing()
 
 
  FlipBuffers(2)
Until KeyboardPushed(#PB_Key_Escape)
Force et sagesse...
Anonyme

Message par Anonyme »

ca ne fonctionne pas avec des z différents :?
tmyke
Messages : 1554
Inscription : lun. 24/juil./2006 6:44
Localisation : vosges (France) 47°54'39.06"N 6°20'06.39"E

Message par tmyke »

Arh, je me replonge dans le code dès que j'ai 5 mn...
Force et sagesse...
Anonyme

Message par Anonyme »

merci mon seigneur :wink:
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Tres sympa !!
J'ai pas eu vraiment le temps de regardé de tres près mais ça m'a fait pensé a quelques choses...
As tu vu ce code sur le forum anglais ?
(source:http://www.purebasic.fr/english/viewtopic.php?t=26657)

Code : Tout sélectionner

#DarkGray = 3158064

Procedure DrawBar(X,Y,Width.f,Height,Value.f,MaxValue,Text$,FullColor,EmptyColor)
  Protected Color
  If Value > MaxValue: Value = MaxValue: EndIf
  Color = RGB((Red(FullColor)-Red(EmptyColor))/MaxValue*Value+Red(EmptyColor), (Green(FullColor)-Green(EmptyColor))/MaxValue*Value+Green(EmptyColor), (Blue(FullColor)-Blue(EmptyColor))/MaxValue*Value+Blue(EmptyColor))
  Box(X,Y,Width,Height,#Gray) ;Border
  Box(X+1,Y+1,Width-2,Height-2,#DarkGray) ;Background
  Box(X+1,Y+1,(Width-2) / MaxValue*Value,Height-2,Color) ;Bar
  DrawText(X+Width/2-TextWidth(Text$)/2,Y+Height/2-TextHeight(Text$)/2,Text$,#White) ;Text
EndProcedure

Define Health = 200

InitKeyboard():InitSprite():OpenScreen(640,480,32,"Test")
Delay(1000)
Repeat
  Delay(40): If Health: Health - 1: EndIf
  FlipBuffers():ClearScreen(#Black)
  If StartDrawing(ScreenOutput())
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawBar(10,10,200,20,Health,200,"Health",#Green,#Red)
    StopDrawing()
  EndIf
  ExamineKeyboard()
Until KeyboardPushed(#PB_Key_Escape)
Pour le degradé il fait ça différemment, (ce qui ne veut pas dire que c'est mieux)
Anonyme

Message par Anonyme »

oui, c'est simple à mettre en oeuvre, mais là, j'ai besoin de cette routine
pour le moteur que tu m'a fait recomençer ^^
j'aimerais pouvoir choisir la couleur de chaque vertex , puis de faire le dégradé entre les vertices pour avoir un zoli rendu ^^
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Lollllllllllll c'est de ma faute alors lollllllll Bon ba je vais reflechir si j'ai une idée... je te dois bien ça :P
Avatar de l’utilisateur
Thyphoon
Messages : 2706
Inscription : mer. 25/août/2004 6:31
Localisation : Eragny
Contact :

Message par Thyphoon »

Bon en cherchant une idée je suis tombé sur ça : (un code trouvé sur le forum anglais...part ...heu ....je sais plus son nom.. :oops:
pas de dégradé mais ça permet de tracer les triangles plein assez rapidement

Code : Tout sélectionner

#FP = 6

Procedure filltriangle(x1,y1,x2,y2,x3,y3,color)

Define.w x, y, x0,y0, dx1, dx2, dx3, scanleftx, scanrightx, leftadd, rightadd, beginx, endx
Define.b bucle

; Sort algorithm using swap method, two iterations is enough to sort an array with 3 items
For bucle = 0 To 1
  If y1>y2 : x0=x2 : x2=x1 : x1=x0 : y0=y2 : y2=y1 : y1=y0 :  EndIf 
  If y2>y3 : x0=x3 : x3=x2:  x2=x0 : y0=y3 : y3=y2 : y2=y0 :  EndIf
Next bucle

If y2 <> y1
  dx1=((x2-x1)<<#FP)/(y2-y1)
EndIf
If y3 <> y1
  dx2=((x3-x1)<<#FP)/(y3-y1)
EndIf
If y3<> y2
  dx3=((x3-x2)<<#FP)/(y3-y2)
EndIf

scanleftx = x1 << #FP
scanrightx = x1 << #FP

If dx1 < dx2
  leftadd=dx1
  rightadd=dx2
Else
  leftadd=dx2
  rightadd=dx1
EndIf

For y = y1 To y2-1
  beginx = scanleftx >> #FP
  endx = scanrightx >> #FP
  LineXY(beginx, y, endx, y, color)
  scanleftx + leftadd
  scanrightx + rightadd
Next y

If dx2 > dx3
  leftadd = dx2
  rightadd = dx3
Else
  leftadd = dx3
  rightadd = dx2
EndIf

For y = y2 To y3
  beginx = scanleftx >> #FP
  endx = scanrightx >> #FP
  LineXY(beginx, y, endx, y, color)
  scanleftx + leftadd
  scanrightx + rightadd
Next y

EndProcedure


Tient d'ailleur si tu veux speeder ton moteur je te conseille de remplacer les plot() par des pointeurs...c'est ce que j'utilise pour mon moteur de lumière dans mon jeu ! :)

Bon je retourne cherche une idée pour melanger 3 vouleurs dans un triangle :D
tmyke
Messages : 1554
Inscription : lun. 24/juil./2006 6:44
Localisation : vosges (France) 47°54'39.06"N 6°20'06.39"E

Message par tmyke »

Cpl.Bator a écrit :ca ne fonctionne pas avec des z différents :?
je comprend pas. C'est sur qu'avec le code comme il est la, si tu fait
Line(10,10,10, 10,10,100, etc...) vue que ta vue est 2D, tu auras sur
l'ecran qu'un point. Mais, si dans la partie lié au 'z-dominant' tu remplace
ton Plot(x,y) par un plot(x,z) (comme si on changeait de repère), cela semble
bien marcher, non ?
Force et sagesse...
Anonyme

Message par Anonyme »

Comme ceci , ca ne marche pas :

Code : Tout sélectionner

DrawLinePtr3D(100,100,1000,250,100,500,RGB(255,0,0),RGB(0,0,255))
j'ai une ligne rouge toute simple. l'ecart doit être trop grand entre les 2 Z, et du coup le pas et quasi nul pour une si petite distance.
A mon avis, faut que je laisse les Z à 0 lors de la prise de distance entre les vertices. mais faut tenir compte des z d'une autre facon, essaye avec ces coordonées (plus haut) et laisse les z à 0.



@Thyphoon , si tu regarde bien le code plus haut, je passe par des pointeurs, j'ai mis plot() pour le forum
Merci pour le triangle, je l'ai déjà pompé :D
tmyke
Messages : 1554
Inscription : lun. 24/juil./2006 6:44
Localisation : vosges (France) 47°54'39.06"N 6°20'06.39"E

Message par tmyke »

C'est une histoire de Distance en effet, car dès que tu as des bornes trop importantes
cela perturbe la fonctionnement. Ce n'est spécifiquement du a l'axe Z, si tu fait par exemple
DrawLine(100,100,100, 1000,100,100, etc...) tu as le meme soucis.

En fait il faut trouver le moyen de normalizer les Pas, quelque soit la distance entre les deux points dans l'espace...
Force et sagesse...
Gratteur
Messages : 147
Inscription : ven. 22/avr./2005 23:02

Message par Gratteur »

Une petite contribution (traduction et optimisation d'un code C de heulin très utile pour créer un moteur 3D ou remplir des triangles :

#largeur = largeur de l'écran
#hauteur = hauteur de l'écran

Code : Tout sélectionner

Structure Segment
  debut.l
  fin.l
EndStructure

Global Dim segmenth.Segment(#hauteur)
For k=0 To #hauteur-1
  segmenth(k)\debut = #MINLONG
  segmenth(k)\fin = #MINLONG
Next k

Procedure InitSegment(x1, y1, x2, y2, *miny, *maxy)
  Protected x, pas, miny, maxy
  If y2 <> y1
    miny = PeekL(*miny)
    maxy = PeekL(*maxy)
    If y2 < y1
      Swap x1, x2
      Swap y1, y2
    EndIf
    x = x1<<8
    pas = ((x2-x1)<<8)/(y2-y1)
    x+pas
    y1+1
    If y1 < miny
      miny = y1
    EndIf
    If y2 > maxy
      maxy = y2
    EndIf
    For y=y1 To y2
      If y >= 0 And y < #hauteur
        If segmenth(y)\debut = #MINLONG
          segmenth(y)\debut = x>>8
        Else
          segmenth(y)\fin = x>>8
        EndIf
        x+pas
      EndIf
    Next y
    PokeL(*miny, miny)
    PokeL(*maxy, maxy)
  EndIf
EndProcedure

Procedure FillTriangle(p.Point(1), couleur=#blanc)
  Protected miny = #hauteur, maxy
  InitSegment(p(0)\x, p(0)\y, p(1)\x, p(1)\y, @miny, @maxy)
  InitSegment(p(1)\x, p(1)\y, p(2)\x, p(2)\y, @miny, @maxy)
  InitSegment(p(2)\x, p(2)\y, p(0)\x, p(0)\y, @miny, @maxy)
  If miny < 0
    miny = 0
  EndIf
  If maxy >= #hauteur
    maxy = #hauteur-1
  EndIf
  For y=miny To maxy
    If segmenth(y)\debut = #MINLONG
      If segmenth(y)\debut >= 0 And segmenth(y)\debut < #largeur
        Plot(segmenth(y)\debut, y, couleur)
      EndIf
    Else
      Hline(segmenth(y)\debut, segmenth(y)\fin, y, couleur)
      segmenth(y)\debut = #MINLONG
      segmenth(y)\fin = #MINLONG
    EndIf
  Next y
EndProcedure
If faut appeler FillTriangle(p.Point(1), couleur=#blanc) avec un tableau dim p.point() des trois sommets du triangle (après projection) et une couleur optionelle.

Code : Tout sélectionner

FillTriangle(p(), couleur)
Edit : J'allais oublier la fonction Hline, c'est cette fonction que tu peux modifier pour avoir un beau dégradé (vu que tu as calculé les positions du début et la fin du segment tu as donc aussi leur longeur).

Code : Tout sélectionner

Procedure Hline(x1, x2, y, couleur=#blanc)
  If y >= 0 And y < #hauteur
    If x1 > x2
      Swap x1, x2
    EndIf
    For x=x1 To x2
      If x >= 0 And x < #largeur
        Plot(x, y, couleur)
      EndIf
    Next x
  EndIf
EndProcedure
Dernière modification par Gratteur le dim. 29/avr./2007 11:51, modifié 1 fois.
Anonyme

Message par Anonyme »

Merci Gratteur, ca m'évitera de recommençer la traduction :D
Répondre