Animation et Draw
ldci2-Feb-2011/15:29:19+1:00
Salut à tous
Pour des besoins de manip, j'ai besoin de créer des animations graphiques qui soient particulièrement fluides (non saccadiques). J'ai fait divers tests dont un dernier, basé sur les gradients de couleurs qui me semble pas mal, mais qui reste encore un peu saccadé. Qui aurait une idée géniale (dans le temps j'utilisais le retrace signal du tube cathodique de l'écran, mais ce n'est plus à la mode avec nos écrans LCD , sniff). Voici le très court code qui encore une fois montre le bon côté de Rebol pour la simplicité (essayez de faire la même chose en Java)


#! /usr/bin/rebol
rebol [Title: "Moving Gradients"]
xoffset: 0x0
velocity: 1
Count: 0
mov: false

spec: [
   fill-pen linear 'xoffset
   repeat 69.4 173.3 0 1 1 0.0.255 255.255.255 0.0.255
   box
]

motion: does [
   while [mov] [
      Count: Count + velocity
      if Count > b/size/x [Count: negate b/offset/x ]
      xoffset/x: Count
      wait 0 ; for mac
      show b
   ]
]

view center-face layout [
across
b: box 800x600 white effect [draw spec]
btn "Start" [mov: true motion]
btn "Stop" [mov: false]
btn "Quit" [Quit]
return
text "Velocity"
sl: slider 200x24 [velocity: sl/data * 15 + 1 vit/text: round/to velocity 0.01 show vit ]
vit: info 100 "1"
]
guest22-Feb-2011/16:02:14+1:00
T'es au max là.
Après ça dépend de la puissance de ta bécanne, des lenteurs inhérentes au moteur graphique AGG, de ton OS et du compilateur utilisé par Carl.

Sur un Core 2 Duo avec XP, c'est fluide mais problème de synchro avec l'interruption VSYNC, mais là rien à faire, Carl ne s'est jamais soucié de se genre d'optimisations dans Rebol.
ldci2-Feb-2011/18:27:35+1:00
Salut Guest
C'est bien ce que je pensais, va falloir faire un code compilé pour augmenter la fluidité. C'est bien dommage car la gestion des gradients avec rebol, c'est nickel
DocKimbel2-Feb-2011/18:50+1:00
@ldci: comme ton animation est circulaire, tu peux essayer de créer les images correspondantes à chaque "offset" de ton gradient sur toute la zone d'affichage, puis les afficher rapidemment en boucle. J'ignore si le résultat sera moins saccadé, mais ça vaut le coup d'essayer.

Une astuce possible pour lisser l'animation des images: construire une image unique de tes gradients mais faisant, disons, 2 x la largeur de la zone d'affichage, puis la faire défiler horizontalement en utilisant le "hardware scrolling", cf. les liens ci-dessous :

http://www.codeconscious.com/rebol/view-notes.html#TheCHANGESfacet
http://www.rebolforces.com/zine/rzine-1-05.html#sect5.2.
ldci2-Feb-2011/21:50:14+1:00
@DocKimbel: j'ai testé les deux solutions que tu évoques, mais ce n'est pas mieux. Dans tous les cas on passe par un décalage d'offset et un draw pour réafficher. Si l'image est gourmande, l'aspect saccadique reste. Il n'y pas de mystère quand on veut quelque chose de parfait pour le scrolling, on doit faire appel à l'assembleur

Procedure Wait_In_Retrace;assembler;
{attend le retour de balayage vertical, réinitialise
en même temps le flip-flop de l'ATC en effectuant
un accès en lecture au registre Input Status 1 }


asm
mov dx,3dah {Input Status 1}
@wait1:
in al,dx
test al,8h
jz @wait1 {balayage actif ? -> terminÇ }
End;


J'avais simplement espéré que AGG avait quelques ressources intéressantes. Dans ce domaine, Rebcode aurait pu apporter quelque chose comme un gain de 20% sur les vitesses de réaffichage.
En tout cas, merci pour les suggestions
ldci3-Feb-2011/14:11:42+1:00
@DocKimbel
La technique avec le hard scrolling est très intéressante pour déplacer une face d'un point A à un point B en utilisant une fonction du type
move-face: func [
   "Move a face to a new offset"
   face [object!]
   new-offset [pair!]
   /relative "Move relative to current position"
   ] [
face/offset: either relative [face/offset + new-offset] [new-offset]
face/changes: 'offset
show face
]
En revanche, je ne suis pas sur que cela fonctionne correctement lorsqu'on fait appel à un draw [image toto offset]
DocKimbel3-Feb-2011/14:57+1:00
@ldci: il me semble que le hard scrolling ne fonctionne que pour déplacer une face (et son contenu, bloc DRAW inclus) par rapport à sa face parent. Ca ne marchera pas pour déplacer une image construite depuis un bloc DRAW par rapport à la face le contenant. Il est néanmoins toujours possible de placer l'image dans face/image plutôt que de passer par DRAW et utiliser le hard scrolling sur cette face pour avoir un déplacement rapide, et eventuellement, fluide.

A propos de ton "hack" en assembleur pour synchroniser avec la VBL (Vertical Blank Line), je me demande si c'est stable et sûr comme technique sur les OS/machines modernes, ce genre d'accès très bas niveau est normalement réservé aux drivers uniquement. De plus, il me semble que ce port est propre à l'architecture PC, je suppose que tu es toujours sur Mac, est-ce que çà marche dans ce cas ?

Un alternative plus sûre serait de passer par l'API de l'OS pour faire cette synchro verticale, en supposant que cette fonctionnalité est bien exposée dans l'API.
DocKimbel3-Feb-2011/15:03:59+1:00
Ah, j'ai enfin trouvé une ressource en ligne documentant un peu les ports E/S video : http://www.seasip.info/VintagePC/cga.html

Visiblement, ces ports sont liés à la carte graphique et non à l'architecture PC, donc ils doivent exister sur toutes machines ayant une carte graphique assurant une certaine compatibilité avec la norme CGA.
ldci3-Feb-2011/17:00:15+1:00
@DocKimbel:
il est néanmoins toujours possible de placer l'image dans face/image plutôt que de passer par DRAW et utiliser le hard scrolling sur cette face pour avoir un déplacement rapide, et eventuellement, fluide

Oui tout à fait la meilleur solution est d'éviter le draw qui est gourmand en ressources (voir les scripts de Maxim Olivier-Adlhoch sur le sujet).
Dans la mesure où mes vitesses d'animation n'ont pas besoin d'être super rapides, je vais garder la solution gradient car elle est très souple et elle me permet de déplacer les gradients en x et y sans problème avec une seule petite fonction minimale

; controls stimulus motion direction
motion: func [to-where mov] [
   while [mov] [
    switch to-where [
          "right"   [ _grad-offset/x: _grad-offset/x + velocity]
          "left"   [ _grad-offset/x: _grad-offset/x - velocity]
          "up" [_grad-offset/y: _grad-offset/y - velocity]
          "down" [_grad-offset/y: _grad-offset/y + velocity]
    ]
      wait 0;
      show stimulus
   ]
]

Pour l'assembleur tu as raison, j'avais développé ces routines à la fin des années 80 (sous DOS!) pour des cartes VGA. Cette technique était associée avec des pointeurs de code et une gestion maison des interruptions... Bon, depuis, j'ai un peu laissé de coté la technique... parce que ce n'est pas génial sur des écrans LCD
Sinon, je suis tjrs avec du Mac OSX, mais aussi du Linux (ZevenOS), Windows et ... Haiku (vieille histoire d'amour pour BeOS )
Merci pour la doc sur les E/S vidéo
A +
ldci3-Feb-2011/19:52:30+1:00
Bien
Voici une version quasi définitive. Si vous voyez des améliorations, elles seront les bienvenues.
#! /usr/bin/rebol
rebol [
   Title: "Moving Gradients"
   Author: "François Jouen"
   Version: 1.0
   Needs: [view 1.3.2]
]

_grad-offset: 0x0 ; this allows directional motion
_grad-start-rng: 90.0 ; to create lines
_grad-stop-rng: 180.0 ;to create lines
_grad-angle: 0 ; 0 for horizontal motion and 90 for vertical motion
_grad-scale-x: 1 ; allows modifying frequency in x range
_grad-scale-y: 1 ; allows modifying frequency in y range
_grad-color-1: silver ; this can be modified for playing with colors
_grad-color-2: snow ; this can be modified for playing with colors
_grad-color-3: silver ; this can be modified for playing with colors


velocity: 1
mov: false
direction: "right"
ssize: 800x600; tested up 1600x1200

; for repeated linear gradient
grad: [
   fill-pen linear '_grad-offset
   repeat '_grad-start-rng '_grad-stop-rng '_grad-angle '_grad-scale-x '_grad-scale-y
   '_grad-color-1
   '_grad-color-2
   '_grad-color-3
   box
]


; controls stimulus motion direction
motion: func [to-where] [
   while [mov] [
    switch to-where [
          "right"   [ _grad-offset/x: _grad-offset/x + velocity]
          "left"   [ _grad-offset/x: _grad-offset/x - velocity]
          "up" [_grad-offset/y: _grad-offset/y - velocity]
          "down" [_grad-offset/y: _grad-offset/y + velocity]
    ]
      wait 0; for mac OS
      show stimulus
   ]
]


MainWin: layout [
   across
   stimulus: box ssize effect [draw grad]
   return
   text "Direction"
   arrow 24x24 effect [fit arrow 0.0.0 0.7 rotate 270 ] [_grad-angle: 0 direction: "left" show stimulus]
   arrow 24x24 effect [fit arrow 0.0.0 0.7 rotate 0] [_grad-angle: 90 direction: "up" show stimulus]
   arrow 24x24 effect [fit arrow 0.0.0 0.7 rotate 180] [_grad-angle: 90 direction: "down" show stimulus]
   arrow 24x24 effect [fit arrow 0.0.0 0.7 rotate 90] [_grad-angle: 0 direction: "right" show stimulus]
   text "Velocity"
   sl: slider 200x24 [velocity: sl/data * 9 + 1 vit/text: round/to velocity 0.01 show vit ]
   vit: info 50 "1"
   btn "Start" [mov: true motion direction ]
   btn "Stop" [mov: false ]
   btn "Zero" [_grad-offset: 0x0 show stimulus]
   btn "Quit" [Quit]
]


view/new center-face MainWin

insert-event-func [
   if (event/type = 'close) and (event/face = MainWin) [quit]
   [event]
]
do-events

Login required to Post.


Powered by RebelBB and REBOL 2.7.8.4.2