com.irr310.i3d.scene.element.I3dElement.java Source code

Java tutorial

Introduction

Here is the source code for com.irr310.i3d.scene.element.I3dElement.java

Source

// 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 com.irr310.i3d.scene.element;

import java.nio.FloatBuffer;

import org.lwjgl.opengl.GL11;

import com.irr310.i3d.I3dContext;
import com.irr310.i3d.scene.I3dCamera;

import fr.def.iss.vd2.lib_v3d.V3DContext;
import fr.def.iss.vd2.lib_v3d.V3DVect3;
import fr.def.iss.vd2.lib_v3d.element.V3DBoundingBox;
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 I3dElement {

    /**
     * Cre un nouvel lment dans le context fournis en paramtre
     */
    public I3dElement() {
        id = I3dContext.getInstance().getSceneManager().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(I3dCamera 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(I3dCamera 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(I3dCamera 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(I3dCamera 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();

    }
}