Animation et Draw | |
ldci | 2-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" ] | |
guest2 | 2-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. | |
ldci | 2-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 | |
DocKimbel | 2-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. | |
ldci | 2-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 | |
ldci | 3-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] | |
DocKimbel | 3-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. | |
DocKimbel | 3-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. | |
ldci | 3-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 + | |
ldci | 3-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. |