1/*
2 * To change this template, choose Tools | Templates
3 * and open the template in the editor.
4 */
5package com.jme3.bullet.control;
6
7import com.jme3.bullet.PhysicsSpace;
8import com.jme3.bullet.collision.shapes.CollisionShape;
9import com.jme3.bullet.objects.PhysicsGhostObject;
10import com.jme3.export.InputCapsule;
11import com.jme3.export.JmeExporter;
12import com.jme3.export.JmeImporter;
13import com.jme3.export.OutputCapsule;
14import com.jme3.math.Quaternion;
15import com.jme3.math.Vector3f;
16import com.jme3.renderer.RenderManager;
17import com.jme3.renderer.ViewPort;
18import com.jme3.scene.Spatial;
19import com.jme3.scene.control.Control;
20import java.io.IOException;
21
22/**
23 * A GhostControl moves with the spatial it is attached to and can be used to check
24 * overlaps with other physics objects (e.g. aggro radius).
25 * @author normenhansen
26 */
27public class GhostControl extends PhysicsGhostObject implements PhysicsControl {
28
29    protected Spatial spatial;
30    protected boolean enabled = true;
31    protected boolean added = false;
32    protected PhysicsSpace space = null;
33    protected boolean applyLocal = false;
34
35    public GhostControl() {
36    }
37
38    public GhostControl(CollisionShape shape) {
39        super(shape);
40    }
41
42    public boolean isApplyPhysicsLocal() {
43        return applyLocal;
44    }
45
46    /**
47     * When set to true, the physics coordinates will be applied to the local
48     * translation of the Spatial
49     * @param applyPhysicsLocal
50     */
51    public void setApplyPhysicsLocal(boolean applyPhysicsLocal) {
52        applyLocal = applyPhysicsLocal;
53    }
54
55    private Vector3f getSpatialTranslation() {
56        if (applyLocal) {
57            return spatial.getLocalTranslation();
58        }
59        return spatial.getWorldTranslation();
60    }
61
62    private Quaternion getSpatialRotation() {
63        if (applyLocal) {
64            return spatial.getLocalRotation();
65        }
66        return spatial.getWorldRotation();
67    }
68
69    public Control cloneForSpatial(Spatial spatial) {
70        GhostControl control = new GhostControl(collisionShape);
71        control.setCcdMotionThreshold(getCcdMotionThreshold());
72        control.setCcdSweptSphereRadius(getCcdSweptSphereRadius());
73        control.setCollideWithGroups(getCollideWithGroups());
74        control.setCollisionGroup(getCollisionGroup());
75        control.setPhysicsLocation(getPhysicsLocation());
76        control.setPhysicsRotation(getPhysicsRotationMatrix());
77        control.setApplyPhysicsLocal(isApplyPhysicsLocal());
78
79        control.setSpatial(spatial);
80        return control;
81    }
82
83    public void setSpatial(Spatial spatial) {
84        if (getUserObject() == null || getUserObject() == this.spatial) {
85            setUserObject(spatial);
86        }
87        this.spatial = spatial;
88        if (spatial == null) {
89            if (getUserObject() == spatial) {
90                setUserObject(null);
91            }
92            return;
93        }
94        setPhysicsLocation(getSpatialTranslation());
95        setPhysicsRotation(getSpatialRotation());
96    }
97
98    public void setEnabled(boolean enabled) {
99        this.enabled = enabled;
100        if (space != null) {
101            if (enabled && !added) {
102                if (spatial != null) {
103                    setPhysicsLocation(getSpatialTranslation());
104                    setPhysicsRotation(getSpatialRotation());
105                }
106                space.addCollisionObject(this);
107                added = true;
108            } else if (!enabled && added) {
109                space.removeCollisionObject(this);
110                added = false;
111            }
112        }
113    }
114
115    public boolean isEnabled() {
116        return enabled;
117    }
118
119    public void update(float tpf) {
120        if (!enabled) {
121            return;
122        }
123        setPhysicsLocation(getSpatialTranslation());
124        setPhysicsRotation(getSpatialRotation());
125    }
126
127    public void render(RenderManager rm, ViewPort vp) {
128        if (enabled && space != null && space.getDebugManager() != null) {
129            if (debugShape == null) {
130                attachDebugShape(space.getDebugManager());
131            }
132            debugShape.setLocalTranslation(spatial.getWorldTranslation());
133            debugShape.setLocalRotation(spatial.getWorldRotation());
134            debugShape.updateLogicalState(0);
135            debugShape.updateGeometricState();
136            rm.renderScene(debugShape, vp);
137        }
138    }
139
140    public void setPhysicsSpace(PhysicsSpace space) {
141        if (space == null) {
142            if (this.space != null) {
143                this.space.removeCollisionObject(this);
144                added = false;
145            }
146        } else {
147            if (this.space == space) {
148                return;
149            }
150            space.addCollisionObject(this);
151            added = true;
152        }
153        this.space = space;
154    }
155
156    public PhysicsSpace getPhysicsSpace() {
157        return space;
158    }
159
160    @Override
161    public void write(JmeExporter ex) throws IOException {
162        super.write(ex);
163        OutputCapsule oc = ex.getCapsule(this);
164        oc.write(enabled, "enabled", true);
165        oc.write(applyLocal, "applyLocalPhysics", false);
166        oc.write(spatial, "spatial", null);
167    }
168
169    @Override
170    public void read(JmeImporter im) throws IOException {
171        super.read(im);
172        InputCapsule ic = im.getCapsule(this);
173        enabled = ic.readBoolean("enabled", true);
174        spatial = (Spatial) ic.readSavable("spatial", null);
175        applyLocal = ic.readBoolean("applyLocalPhysics", false);
176        setUserObject(spatial);
177    }
178}
179