Java tutorial
// Copyright 2010 DEF // // This file is part of V3dScene. // // V3dScene is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // V3dScene is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with V3dScene. If not, see <http://www.gnu.org/licenses/>. package fr.def.iss.vd2.lib_v3d.element; import java.nio.FloatBuffer; import org.lwjgl.opengl.GL11; import fr.def.iss.vd2.lib_v3d.V3DContext; import fr.def.iss.vd2.lib_v3d.V3DContextElement; import fr.def.iss.vd2.lib_v3d.V3DVect3; import fr.def.iss.vd2.lib_v3d.camera.V3DCamera; import fr.def.iss.vd2.lib_v3d.element.animation.V3DAnimation; import fr.def.iss.vd2.lib_v3d.element.animation.V3DNullAnimation; /** * Un lement reprsente un objet prsent dans une scne. * * <pre> * Une scne contient des lments organiss en arborescence. Si un lment * ne peut pas intrinsquement possder des fils, certains types d'lments le * peuvent. * * Chaque lment possdent une position, un rotation et une chelle qui sont * relatives leur parent dans l'arborescence. Chaque lment possde aussi une * mthode de dessin qui va lui permettre de se dessiner sur le canvas. Les * lments ayant des fils vont souvent aussi dessiner leurs enfants. * * V3DElement est une classe abstraite. Les lments nativement disponible dans * V3DScene sont lists ici. * - Les lments de dessin permettent de dessiner des formes 2d ou 3d dans la * scne : * - V3DRectangle : dessine un rectangle en 2d. * - V3DLine : dessine une ligne. * - V3DBox : dessine un paralllpipde rectangle. * - V3DCircle : dessine un cercle en 2d. * - V3DPoint : dessine un point. * - V3DPolygon : dessine un polygon convexe, concave et/ou trou. * - V3DPolygonBox : dessine un prisme dont le polygone directeur peut tre * convexe, concave et/ou trou. * - V3DPolygonWall : dessine une surface prismatique dont le polygone * directeur peut tre convexe, concave et/ou trou. * - V3DSprite : dessine un carr textur. * - V3DrawElement : dessine un modle 2d ou 3d stock au format v3draw. * * - Les lments d'arborescence permettent de crer un arbre d'lments * afficher : * - V3DGroupElement : lment conteneur qui dessine ses fils dans l'ordre * d'ajout. * - V3DOrderedGroupElement : lment conteneur qui dessine ses fils dans * l'ordre choisi. * - V3DNeutralElement : lment transparent qui se contente de dessiner * son unique fils. Cet lement peut servir choisir si une rotation est * applique avant ou aprs la translation. * * - Les modificateurs permettent de configurer le dessin de leur sous-arbre: * - V3DColorElement : definit la couleur appliquer pour le dessin du * sous-arbre fils. * - V3DAbsoluteSizeElement : contraint le sous-arbre fils avoir toujours * une taille constante en pixels par rapport l'cran, quel que soit le * zoom de la camra. * - V3DNoDepthElement : dessine le sous-arbre fils en ignorant la profondeur * des objets (masquage ralis par le Z-buffer). * * Un lement peut se voir attribuer une animation (V3DAnimation) qui peut en * modifier le rendu ou mme empcher son affichage. * * Il est possible de masquer totalement un lment et ses fils en jouant sur * l'attribut "visible". * * Une des fonctionalits de V3DScene est de fournir la liste des lments * actuellement sous le curseur de la souris ou de ragir aux clics sur des * lments. Ces fonctionnalits utilisent un mcanisme appel picking qui * qui consiste dessiner une petite scene dans un cadre de quelques pixels * autour du curseur de la souris et d'enregistrer la liste des objets. * Aprs chaque rendu de scne, une autre passe de rendu appele "select" est * faite autour du curseur. Mais en fonction des besoins, on veut pouvoir * choisir prcisement quels sont les objets qui peuvent tre "selectable" et * apparaitre dans la liste des lments sous la souris. * * Pour configurer le select prcisement, il faut utiliser 2 attributs : * tangible et selectable. * Par dfaut, aucun lment n'est selectable et tous sont tangibles. * * On distingue 3 cas: * - tangible et selectable : l'lment peut tre selectionn. Il ne compte * pas pour ses parents et compte pour ses enfant qui ne sont pas * selectable. * - tangible et non selectable : l'lement ne peut pas tre selectionnn mais * compte pour son parent selectionnable le plus proche. Ses enfants * selectable peuvent tre selectionnable. * - non tangible : cet lment ne peut pas tre selectionn, ne compte pas * pour ses parents et aucun de ses enfants ne peut tre selectionn. * * Exemple d'utilisation de tangible et selectable. * * Supposons que le graphe de scne ressemble cela : * * * racine de la scne * | * +-------------+-------------+ * | | * * plan (route) * groupe (vlo) * | * | * +-------------------------+------+--------------------+ * | | | * * cylindre (roue avant) * cylindre (roue arrire) * boite (cadre) * * * Voici une version allge: * * * * | * +----+----+ * | | * * P * V * | * +---------+---------+ * | | | * * R1 * R2 * C * * Pour dcrire les 3 cas pour chaque lment, voici le formalisme utilis: * - (s) : selectable et tangible * - (t) : tanglible non selectable * - (0) : non tangible * * Nous considrerons que le dessins des objets P, R1, R2 et C se trouvent sous * la souris et qu'ils sont tous potentiellement selectionnable avec les bons * rglages. V, en tant que groupe lement ne dessine rien lui mme mais utilise * ses 3 fils pour se dessiner. * * Exemple 1: Tous les objets tangibles * * * * | * +----+----+ * | | * * P (t) * V (t) * | * +---------+---------+ * | | | * * R1 (t) * R2 (t) * C (t) * * Rsulat : []. Aucun lment n'est selectionn car aucun lment n'est * selectionnable et tangible. * * Exemple 2: Un lments feuille tangible et selectable * * * * | * +----+----+ * | | * * P (s) * V (t) * | * +---------+---------+ * | | | * * R1 (t) * R2 (t) * C (t) * * Rsulat : [P]. P est selectionn car il est selectionnable et tangible et * produit un dessin. * * Exemple 3: Un lment non feuille tangible et selectable * * * * | * +----+----+ * | | * * P (s) * V (s) * | * +---------+---------+ * | | | * * R1 (t) * R2 (t) * C (t) * * Rsulat : [P, V]. P est selectionn pour les mme raisons que dans * l'exemple 2. V l'est aussi car il est selectionnable et tangible et mme s'il * ne produit pas de dessin, ses fils R1, R2 et C ne sont pas selectable et * produisent un dessin et comptent donc pour V. * * Exemple 4: Un lments non feuille tangible et selectable dont aucune * feuille est tangible. * * * * | * +----+----+ * | | * * P (s) * V (s) * | * +---------+---------+ * | | | * * R1 (0) * R2 (0) * C (0) * * Rsulat : [P]. P est selectionn pour les mme raisons que dans l'exemple 2. * V n'est pas selectionn car bien que selectable et tangible, ni lui ni des * fils qui compte pour lui ne produisent de dessin. * * Exemple 5: Un lments non feuille tangible et selectable dont tous les fils * sont aussi tangible et selectable. * * * * | * +----+----+ * | | * * P (s) * V (s) * | * +---------+---------+ * | | | * * R1 (s) * R2 (s) * C (s) * * Rsulat : [P, R1, R2, C]. P, R1, R2 et C sont selectable et tangible et * produisent un dessin, donc ils sont selectionns. V n'est pas * selectionn car bien que selectable et tangible, ses fils tant aussi * selectable, ils produisent un dessin pour eux mme. * * Exemple 6: Un lment non feuille tangible et selectable dont tous les fils * sont aussi tangible et selectable sauf un qui est juste tangible. * * * * | * +----+----+ * | | * * P (s) * V (s) * | * +---------+---------+ * | | | * * R1 (s) * R2 (t) * C (s) * * Rsulat : [P, R1, C, V]. P, R1 et C sont selectable et tangible et * produisent un dessin donc ils sont selectionns. V est selectionn, R2 dessine * pour lui. * * Dans l'exemple 6, imaginons que l'on deplace la souris de tel sorte qu'elle ne * survole plus que le dessin de R1, alors le rsultat sera [R1]. Si la souris * ne survolle que R2, le rsultat sera [V]. * </pre> * * @author fberto */ abstract public class V3DElement extends V3DContextElement { /** * Cre un nouvel lment dans le context fournis en paramtre * * @param context */ public V3DElement(V3DContext context) { super(context); id = context.getIdAllocator().getNewId(this); } public V3DVect3 getPosition() { return position; } public void setPosition(V3DVect3 position) { this.position.copy(position); } public V3DVect3 getRotation() { return rotation; } public void setRotation(V3DVect3 rotation) { this.rotation = rotation; } public V3DVect3 getScale() { return scale; } public void setScale(V3DVect3 scale) { this.scale = scale; } public void setPosition(float x, float y, float z) { this.position.x = x; this.position.y = y; this.position.z = z; } public void setRotation(float x, float y, float z) { this.rotation.x = x; this.rotation.y = y; this.rotation.z = z; } public void setTransformMatrix(FloatBuffer matrix) { this.transformMatrix = matrix; this.position.x = matrix.get(12); this.position.y = matrix.get(13); this.position.z = matrix.get(14); } public void setScale(float x, float y, float z) { this.scale.x = x; this.scale.y = y; this.scale.z = z; } public void setScale(float scale) { this.scale.x = scale; this.scale.y = scale; this.scale.z = scale; } /** * Renvoie la boite englobante * * @return */ abstract public V3DBoundingBox getBoundingBox(); /** * Permet de choisir ce qui sera dessin. Utilis cette fonction masque la * bounding box si elle tait affiche * * @param b * active ou dsactive le rendu normal */ public void setShowMode(boolean b) { setShowMode(b, false); } /** * Permet de choisir ce qui sera dessin. * * @param shape * active ou dsactive le rendu normal * @param boundingBox * active ou dsactive le rendu de la bounding box */ public void setShowMode(boolean shape, boolean boundingBox) { showShape = shape; showBoundingBox = boundingBox; } /** * Dfinie l'animation de l'lment * * @param animation */ public void setAnimation(V3DAnimation animation) { this.animation = animation; } public boolean isShowShape() { return showShape; } public boolean isShowBoundingBox() { return showBoundingBox; } public boolean isSelectable() { return selectable; } public void setSelectable(boolean selectable) { this.selectable = selectable; } public boolean isTangible() { return tangible; } public void setTangible(boolean tangible) { this.tangible = tangible; } public void setVisible(boolean visible) { this.visible = visible; } // // ------------------ // Private stuff // ------------------ // private Boolean inited = false; private V3DVect3 position = new V3DVect3(0, 0, 0); private V3DVect3 rotation = new V3DVect3(0, 0, 0); private FloatBuffer transformMatrix = null; private V3DVect3 scale = new V3DVect3(1, 1, 1); private V3DAnimation animation = new V3DNullAnimation(); private boolean showBoundingBox = false; private boolean showShape = true; private boolean selectable = false; private boolean tangible = true; private boolean visible = true; private long id = 0; /** * Internal public method Mthode principal du rendu d'un lment. Cette * mthode appelle le code de rendu spcifique de l'lment via la mthode * doDisplay si ncessaire. * * @param gl * context gl du rendu * @param camera * point de vue */ final public void display(V3DCamera camera) { if (!visible) { return; } if (!inited) { init(); } GL11.glPushMatrix(); if (transformMatrix != null) { GL11.glMultMatrix(transformMatrix); } else { if (rotation.x != 0) { GL11.glRotatef(rotation.x, 1, 0, 0); } if (rotation.y != 0) { GL11.glRotatef(rotation.y, 0, 1, 0); } if (rotation.z != 0) { GL11.glRotatef(rotation.z, 0, 0, 1); } if (position.x != 0 || position.y != 0 || position.z != 0) { GL11.glTranslatef(position.x, position.y, position.z); } } if (scale.x != 1 || scale.y != 1 || scale.z != 1) { GL11.glScalef(scale.x, scale.y, scale.z); } animation.preDisplay(); if (animation.doDisplay()) { if (showShape) { doDisplay(camera); } if (showBoundingBox) { getBoundingBox().display(); } } animation.postDisplay(); GL11.glPopMatrix(); } /** * Internal public method Mthode principal de l'initialisation d'un * lment. Cette mthode appelle le code d'initialisation spcifique de * l'lment via la mthode doInit si ncessaire. * * @param gl * context gl de l'initialisation */ final public void init() { if (!inited) { inited = true; doInit(); } } /** * Internal public method Mthode appel par init. Contient le code * spcifique d'initialisation de l'lment * * @param gl */ abstract protected void doInit(); /** * Internal public method Mthode appel par display. Contient le code * spcifique de rendu de l'lment * * @param gl * @param camera */ abstract protected void doDisplay(V3DCamera camera); /** * Internal public method Mthode appel par select. Contient le code * spcifique du rendu pour la selection de l'lment. Par dfautl, le rendu * pour la selection est le dessin de la bounding box de l'lment. * * @param gl * @param camera * @param parentId */ protected void doSelect(V3DCamera camera, long parentId) { if (parentId != 0) { getBoundingBox().displayFaces(); } } /** * Internal public method Renvoie l'tat d'initialisation de l'lment * * @param gl * context gl courant. Si le context gl change, il faut * initialiser l'lment nouveau. * @return tat d'initialisation de l'lment */ public boolean isInit() { return inited; } /** * Internal public method Mthode principal du rendu de selection d'un * lment. Cette mthode appelle le code de rendu de selection spcifique * de l'lment via la mthode doSelect si ncessaire. Les animations * n'entrent pas en jeu dans le rendu de selection. * * @param gl * context gl du rendu de selection * @param camera * point de vue */ final public void select(V3DCamera camera, long parentId) { if (!inited) { init(); } if (!isTangible() || !showShape) { return; } GL11.glPushMatrix(); // TODO: verify this cast. Maybe change id from long to int if (selectable) { GL11.glLoadName((int) id); } if (rotation.x != 0) { GL11.glRotatef(rotation.x, 1, 0, 0); } if (rotation.y != 0) { GL11.glRotatef(rotation.y, 0, 1, 0); } if (rotation.z != 0) { GL11.glRotatef(rotation.z, 0, 0, 1); } if (position.x != 0 || position.y != 0 || position.z != 0) { GL11.glTranslatef(position.x, position.y, position.z); } if (scale.x != 1 || scale.y != 1 || scale.z != 1) { GL11.glScalef(scale.x, scale.y, scale.z); } if (selectable) { doSelect(camera, id); } else { doSelect(camera, parentId); } if (selectable) { GL11.glLoadName((int) parentId); } GL11.glPopMatrix(); } }