// Path: extensions/bullet/src/main/java/com/simsilica/bullet/Contact.java
// public class Contact implements EntityComponent {
// 
//     private EntityId entity1;
//     private int type1;
//     
//     private EntityId entity2;
//     private int type2;
//  
//     private int typeMask;
//     
//     private Vector3f location;   
//     private Vector3f normal;
//     private float energy;   
// 
//     private Contact() {
//     }
//  
//     public Contact( EntityId entity1, int type1, EntityId entity2, int type2,
//                     Vector3f location, Vector3f normal, float energy ) {
//         this.entity1 = entity1;
//         this.type1 = type1;
//         this.entity2 = entity2;
//         this.type2 = type2;
//         this.typeMask = type1 | type2;
//         this.location = location;
//         this.normal = normal; 
//         this.energy = energy;
//     }   
//  
//     public static Contact create( EntityPhysicsObject object1, EntityPhysicsObject object2,
//                                   Vector3f wp, Vector3f normal, float energy ) {
//         Contact result = new Contact();
//         if( object1 != null ) {
//             result.entity1 = object1.getId();
//             result.type1 = object1.getMassType();
//         }
//         if( object2 != null ) {
//             result.entity2 = object2.getId();
//             result.type2 = object2.getMassType();
//         }
//         result.typeMask = result.type1 | result.type2;
//         result.location = wp;
//         result.normal = normal;
//         result.energy = energy;
//         
//         return result;
//     } 
//  
//     public EntityId getEntity1() {
//         return entity1;
//     }
//     
//     public int getType1() {
//         return type1;
//     }
//     
//     public EntityId getEntity2() {
//         return entity2;
//     }
//     
//     public int getType2() {
//         return type2;
//     }
//  
//     public int getTypeMask() {
//         return typeMask;
//     }   
//     
//     public Vector3f getLocation() {
//         return location;
//     }
// 
//     public Vector3f getNormal() {
//         return normal;
//     }
//     
//     public float getEnergy() {
//         return energy;
//     }
// 
//     @Override
//     public String toString() {
//         return MoreObjects.toStringHelper(getClass().getSimpleName())
//                 //.omitNullValues()
//                 .add("entity1", entity1)
//                 .add("type1", "0b" + Integer.toBinaryString(type1))
//                 .add("entity2", entity2)
//                 .add("type2", "0b" + Integer.toBinaryString(type2))
//                 .add("location", location)
//                 .add("normal", normal)
//                 .add("energy", energy)
//                 .add("typeMask", typeMask)
//                 .toString(); 
//     } 
// }


import java.util.*;
import org.slf4j.*;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.util.DebugShapeFactory;
import com.jme3.material.Material;
import com.jme3.material.MatParamOverride;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.*;
import com.jme3.scene.shape.Box;
import com.jme3.scene.debug.Arrow;
import com.jme3.shader.VarType;
import com.simsilica.es.*;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.bullet.Contact;

 
        this.debugRoot = new Node("contactDebugRoot");
        this.contacts = new ContactDebugContainer(ed);
    }
    
    @Override
    protected void cleanup( Application app ) {
    }
    
    @Override
    protected void onEnable() {
        ((SimpleApplication)getApplication()).getRootNode().attachChild(debugRoot);       
        contacts.start();
    }
    
    @Override 
    public void update( float tpf ) {
        contacts.update();
        updateContactViews();
    }
    
    @Override
    protected void onDisable() {
        contacts.stop();
        debugRoot.removeFromParent();
    }
 
    protected void updateContactViews() {
        // Try to reuse items when we can
        int i = 0;

// Path: extensions/bullet/src/main/java/com/simsilica/bullet/Contact.java
// public class Contact implements EntityComponent {
// 
//     private EntityId entity1;
//     private int type1;
//     
//     private EntityId entity2;
//     private int type2;
//  
//     private int typeMask;
//     
//     private Vector3f location;   
//     private Vector3f normal;
//     private float energy;   
// 
//     private Contact() {
//     }
//  
//     public Contact( EntityId entity1, int type1, EntityId entity2, int type2,
//                     Vector3f location, Vector3f normal, float energy ) {
//         this.entity1 = entity1;
//         this.type1 = type1;
//         this.entity2 = entity2;
//         this.type2 = type2;
//         this.typeMask = type1 | type2;
//         this.location = location;
//         this.normal = normal; 
//         this.energy = energy;
//     }   
//  
//     public static Contact create( EntityPhysicsObject object1, EntityPhysicsObject object2,
//                                   Vector3f wp, Vector3f normal, float energy ) {
//         Contact result = new Contact();
//         if( object1 != null ) {
//             result.entity1 = object1.getId();
//             result.type1 = object1.getMassType();
//         }
//         if( object2 != null ) {
//             result.entity2 = object2.getId();
//             result.type2 = object2.getMassType();
//         }
//         result.typeMask = result.type1 | result.type2;
//         result.location = wp;
//         result.normal = normal;
//         result.energy = energy;
//         
//         return result;
//     } 
//  
//     public EntityId getEntity1() {
//         return entity1;
//     }
//     
//     public int getType1() {
//         return type1;
//     }
//     
//     public EntityId getEntity2() {
//         return entity2;
//     }
//     
//     public int getType2() {
//         return type2;
//     }
//  
//     public int getTypeMask() {
//         return typeMask;
//     }   
//     
//     public Vector3f getLocation() {
//         return location;
//     }
// 
//     public Vector3f getNormal() {
//         return normal;
//     }
//     
//     public float getEnergy() {
//         return energy;
//     }
// 
//     @Override
//     public String toString() {
//         return MoreObjects.toStringHelper(getClass().getSimpleName())
//                 //.omitNullValues()
//                 .add("entity1", entity1)
//                 .add("type1", "0b" + Integer.toBinaryString(type1))
//                 .add("entity2", entity2)
//                 .add("type2", "0b" + Integer.toBinaryString(type2))
//                 .add("location", location)
//                 .add("normal", normal)
//                 .add("energy", energy)
//                 .add("typeMask", typeMask)
//                 .toString(); 
//     } 
// }


// Path: extensions/bullet/src/main/java/com/simsilica/bullet/debug/ContactDebugState.java
import java.util.*;
import org.slf4j.*;
import com.jme3.app.Application;
import com.jme3.app.SimpleApplication;
import com.jme3.app.state.BaseAppState;
import com.jme3.bullet.collision.shapes.CollisionShape;
import com.jme3.bullet.util.DebugShapeFactory;
import com.jme3.material.Material;
import com.jme3.material.MatParamOverride;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.*;
import com.jme3.scene.shape.Box;
import com.jme3.scene.debug.Arrow;
import com.jme3.shader.VarType;
import com.simsilica.es.*;
import com.simsilica.lemur.GuiGlobals;
import com.simsilica.bullet.Contact;

 
        this.debugRoot = new Node("contactDebugRoot");
        this.contacts = new ContactDebugContainer(ed);
    }
    
    @Override
    protected void cleanup( Application app ) {
    }
    
    @Override
    protected void onEnable() {
        ((SimpleApplication)getApplication()).getRootNode().attachChild(debugRoot);       
        contacts.start();
    }
    
    @Override 
    public void update( float tpf ) {
        contacts.update();
        updateContactViews();
    }
    
    @Override
    protected void onDisable() {
        contacts.stop();
        debugRoot.removeFromParent();
    }
 
    protected void updateContactViews() {
        // Try to reuse items when we can
        int i = 0;

        for( Contact c : contacts.getArray() ) {
