Chapter 1. Idées et principes

Table of Contents
Le graphe de scéne (scene graph)
Le graphe de contrôle logique - gestion des événements d'entrée - input event handling
MVC

Le graphe de scéne (scene graph)

Une différence centrale entre le serveur Berlin et les autres serveurs d'affichage que vous avez du rencontrer est que Berlin maintient un graphe abstrait détaillé de la scène courante dans sa propre zone de mémoire. Cela signifie que, plutôt que de demander aux applications clientes de repeindre chaque fenêtre lorsqu'un changement quelconque survient, la pluspart du mécanisme de reaffichage est contenu à l'intérieur du serveur.

Structure du graphe (graph structure)

Le graphe de scéne ressemble d'une façon abstraite à un arbre. C'est-à-dire qu'il y a un certain nombre de noeuds (appelés "Illustrations" ou "Graphics"), qui sont connectés ensemble dans une relation transitive parent/enfant. La signification de cette relation est un hybride d'un certain nombre de concepts intuitivement lié.

Du point de vue logique (logical containment)

L'idée de base de la relation parent/enfant est qu'elle exprime le contenu logique de l'enfant à l'intérieur du parent. Cela signifie, à la fois que l'enfant occupe un sous-ensemble de l'espace dans la scéne que le parent occupe, et à la fois que le parent est, d'une certaine manière, responsable de son enfant. Un parent ordonnance l'agencement et l'affichage de ses enfants et peut jouer un rôle de container dans la gestion de la mémoire, la distribution d'événements, etc ...

Au sujet des transformations (transformational containment)

Puisque le graphe de scéne est actuellement stocké dans des valeurs à virgule flotante à double-précision, et puisque n'importe quelle illustration (graphic) peut etre sujet à des transformations linéaires arbitraires dans la scéne, la relation parent/enfant entre les illustrations s'étend naturellement à la composition des transformations linéaires. C'est-à-dire que n'importe quel enfant est sensé non seulement être le sujet de ses propres transformations linéaires mais aussi au produit cumulé de tous les transformations de ses parents. Ce qui signifie qu'en pratique, s'il réussit à faire un changement d'échelle, , à inverser ou à faire une rotation à une fenêtre, tout ce qu'il "contient" changera d'échelle, , sera inverser ou fera une rotation avec elle. Ce comportement peut être desactivé dans les cas où il est indésirable, cependant, il va bien avec une des intuitions physiques donc il est inclus dans la sémantique générale de la relation parent/enfant.

Partage (sharing)

Il y a des instances pour lesquelles il est désirable de pouvoir partager des enfants entre de multiples parents dans un graphe de scéne. Cela fait typiquement référence aux objets "poids plumes", et donne toute sa signification au fait que le graphe de scéne ne soit pas stocké structurellement comme un vrai arbre ; bien qu'il soit fréquement représenté comme un arbre et que cette technique soit utilisé uniquement dans le cas des objets poids plumes pour être plus efficace. On pourrait le voir comme un problème "sous-jacent", mais il est fondamental dans notre conception et doit bien être compris, au moins en passant, pour bien comprendre les sections suivantes, sur le mode de la visite.

Motivation sur l'efficacité (efficiency motivation)

Stocker un grand nombre de petit objets peut fréquemment avoir un coût important, en terme de mémoire. Particulièrement lors de la fourniture d'objets relativement statique comme une icône ou un glyph textuel. Cependent, nous ne désirons pas gérer des cas spéciaux puisque cela compliquera notre code. Donc, dans le but d'améliorer le rendement, spécialement dans le cas très important des textes, nous gardons uniquement une seule copie de chaque objet et lui permettons d'apparaître dans plusieurs places logiques dans le graphe de scéne.

Chemin (trails)

Bien que chaque illustration (graphics) peut apparaître dans plusieurs endroits, si on fait respecter la structure DAG (Directed, Acyclic Graph, graph Acyclique Dirigé) sur notre scéne, nous pouvons garder une caractéristique utile : le problème n'est pas de savoir combien de chemins existe dans le graphe, il reste toujours possible de construire un vrai arbre avec exactement la même apparence/signification logique. C'est-à-dire que, s'il existe un parent P avec un enfant E relié par 2 liaisons distinctes à P, on peut donc, en principe, construire un arbre avec le même parent P ayant 2 enfants E1 et E2, chacun des deux étant juste une copie identique de E. Ce processus peut être répété n'importe où dans le graphe de scéne où il y aurait 2 différents "chemins" principaux à partir de la racine du graphe jusqu'à un enfant donné. Bien que nous ne construisons pas explicitement cet arbre, il est facile maintenant de voir que nous pouvons "imaginer", nous-même, être traversé de la même façon qu'un arbre "applati" à chaque fois que nous traversons le graphe de scéne, en maintennant simplement une pile dont les liens seraient suivis à partir de la racine du graphe jusqu'à l'illustation suivante.

En fait, c'est ce que nos traverses font, donc le fait d'avoir de multiple parents pour chaque enfant est largement caché par le dévelopeur. La seule raison que nous mentionnons ce fait ici, est pour vous rassurez que la condition d'avoir de multiples parents n'est pas un problème important et pour expliquer pourquoi les traversals font tous ce travail.

Externalisation de l'état

Dans le but de comprendre le concept de trace, il est important de realiser qu'une illustration ne peut pas stocker surement une copie de ses informations de disposition ou de transformations cumulatées, puisqu'il peut prendre plusieurs positions à l'écran, plusieurs d'entre eux peuvent avoir différents transformations cumulées. Ainsi, il peut stocker uniquement des informations "relatives" à propos de ses besoins pour sa disposition et possède son état réel calculé à la volé. Ceci s'appelle "externaliser" son état ; dans Berlin, nous essayons d'externaliser autant d'état pour chaque illustration (graphics) que possible. Partiellement ceci est fait pour faciliter la sauvegarde de la mémoire mentionné précédemment, mais cela simplifie aussi la tâche de maintenance des valeurs correctes pour la disposition et les transformations cumulatives, qui sont très dynamiques au début. Puisque nous les calculons à la volée, de tels valeurs ne sont jamais "desynchrone" par rapport à une autre.

Les traverses (traversal)

Le graphe de scéne est sujet à quelques opérations "massives", tel que delivrer des événements et dessiner. Ces opérations sont encapsulées dans des objets d'état, appelé Traverses.

Un algorithme générique

L'algorithme du traverse est un "parcours" générique dans le graphe de scéne. Cela peut être soit d'abord la profondeur soit d'abord la largeur à chaque noeud, et peut y appliquer une opérations parmi un certain nombre. La caractèristique commune aux traverses est qu'ils calculent l'état externalisé de chaque noeud pendant leur passage, donc le noeud peut "continuer à lire" son état alors qu'il est parcourru.

Modifier l'écran

Bien sur, un graphe de scéne statique n'est pas intéressant ; le but d'un systèle de fenêtrage est de permettre aux utilisateurs d'interagir avec l'ordinateur. Nous différons pour l'instant la discussion sur la manière exacte dont les événements d'un utilisateur sont transformés en modifications sur l'applicattion et nous nous consacrerons sur la manière dont les changements sur le graphe de scéne sont propagés vers l'écran. La fonction de reaffichage basique décrite ici est invoqué par un noeud illustration par appel à this->needredraw(), qui calcule les régions endommagées de l'illustration et lance les requêtes de reaffichage à partir du thread de dessin.

allocation

Une illustration peut apparaître un certain nombres de fois dans différents endroits dans un graphe de scéne, donc la première chose qu'une illustration doit faire lorsqu'il met à jour son apparence sur l'écran c'est de travailler exactement où il apparait. La réponse à cette question n'est pas une unique position -- c'est plutôt une liste de régions, chacune d'entre elles représentant une position séparée sur l'écran où l'illustration apparaît. Cette liste est appelée Allocation d'une illustration et il est d'une importance centrale pour le système de reaffichage.

Le calcul d'allocations est un appel récursif, qui "remonte vers" chacun de ses parents et leurs transformations. Chaque parent calcule l'allocation de l'enfant en remontant chacun de ses parents, etc. Les racines sont éventuellement atteintes (oui les racines : il peut y avoir plus d'un écran montrant le même graphe) et il retournera les régions de l'écran. Bien qu'il semble y avoir pas mal d'étapes, tout se passe dans un processus, en suivant des pointeurs, donc le calcul d'allocation est, en général, très rapide.

Dégats

Dans le cas d'un needredraw(), les allocations du illustration sont tous fusionnées ensemble dans un objet Region que l'illustration construit, appelé "région endommagée". La liste d'Allocation contient une référence vers un objet Screen, que l'illustration insérera ensuite dans la région endommagée. Il fait la queue pour réaffichage que le thread d'affichage enverra à une traverse de dessin.

Traverse de dessin

Les objets DrawTraversal sont des objets que le tread de dessin delaisser au graphe de scéne, s'occupant du rendu des objets qui coupent la région endommagée. Chaque traverse de dessin contiendra donc une région endommagé, et testera l'intersection de chaque noeud pendant son passage. Si le noeud passe le test d'intersection, il sera traversé et aura accès au DrawingKit de la traverse, qui peut, par la suite, être utilisé pour dessiner sur le périphérique géré par la traverse.

Positionnement dynamique

Les détails techniques du kit de dessin (lignes, chemins, peinture, textures) ne sont pas utile en profondeur à ce niveau ; nous reportons leur discussion dans un chapitre suivant. Cependant, un point important à connaitre est que la disposition (coordonnées, taille, alignement) des illustrations est, comme leurs positions et transformations, calculé dynamiquement par chaque traverse. Les détails de l'algorithme de disposition sont un peu compliqués, donc ils seront également reportés. Il suffit de dire que l'abstraction de la disposition est fait pour les systèmes basés sur des contraintes locales telles que l'emballage des boîtes, les concepts de composition tels que les "ressorts" et la "glu", positionnement absolu, voire plus.