/examples/advanced/physics/physicsShapes/PhysicsRectangle.java

http://mt4j.googlecode.com/ · Java · 490 lines · 300 code · 100 blank · 90 comment · 33 complexity · 4a0b35eaeab64c2630914ee9827be662 MD5 · raw file

  1. package advanced.physics.physicsShapes;
  2. import java.util.List;
  3. import javax.media.opengl.glu.GLU;
  4. import org.jbox2d.collision.shapes.PolygonDef;
  5. import org.jbox2d.common.Vec2;
  6. import org.jbox2d.dynamics.Body;
  7. import org.jbox2d.dynamics.BodyDef;
  8. import org.jbox2d.dynamics.World;
  9. import org.mt4j.MTApplication;
  10. import org.mt4j.components.MTComponent;
  11. import org.mt4j.components.bounds.BoundsArbitraryPlanarPolygon;
  12. import org.mt4j.components.bounds.IBoundingShape;
  13. import org.mt4j.components.visibleComponents.shapes.GeometryInfo;
  14. import org.mt4j.components.visibleComponents.shapes.MTRectangle;
  15. import org.mt4j.input.inputProcessors.componentProcessors.rotateProcessor.RotateProcessor;
  16. import org.mt4j.input.inputProcessors.componentProcessors.scaleProcessor.ScaleProcessor;
  17. import org.mt4j.util.math.Vector3D;
  18. import org.mt4j.util.math.Vertex;
  19. import org.mt4j.util.opengl.GluTrianglulator;
  20. import processing.core.PApplet;
  21. import processing.core.PGraphics;
  22. import processing.core.PImage;
  23. import advanced.physics.util.PhysicsHelper;
  24. public class PhysicsRectangle extends MTRectangle implements IPhysicsComponent{
  25. private float angle;
  26. private boolean drawBounds;
  27. private World world;
  28. private Body body;
  29. private float density;
  30. private float friction;
  31. private float restituion;
  32. /*
  33. PhysicsRectangle rect = new PhysicsRectangle(new Vector3D(400,200), 100,150, app, world, 0.6f, 0.4f, 0.2f, scale);
  34. rect.setNoStroke(true);
  35. PhysicsHelper.addDragJoint(world, rect, rect.getBody().isDynamic(), scale);
  36. physObjGroup.addChild(rect);
  37. */
  38. public PhysicsRectangle(
  39. Vector3D centerPosition,
  40. float width, float height, PApplet applet,
  41. World world, float density, float friction, float restitution, float scale
  42. ) {
  43. super(applet, 0, 0, PhysicsHelper.scaleDown(width, scale), PhysicsHelper.scaleDown(height, scale));
  44. this.angle = 0;
  45. this.drawBounds = false;
  46. this.world = world;
  47. this.density = density;
  48. this.friction = friction;
  49. this.restituion = restitution;
  50. Vector3D scaledPos = PhysicsHelper.scaleDown(centerPosition.getCopy(), scale);
  51. // PhysicsHelper.scaleDown(centerPosition, scale);
  52. // centerPosition.scaleLocal(1f/scale);
  53. BodyDef dymBodyDef = new BodyDef();
  54. // dymBodyDef.position = new Vec2(pos.x, pos.y);
  55. dymBodyDef.position = new Vec2(scaledPos.x, scaledPos.y);//FIXME WORKS?
  56. this.bodyDefB4CreationCallback(dymBodyDef);
  57. this.body = world.createBody(dymBodyDef);
  58. PolygonDef dymShapeDef = new PolygonDef();
  59. dymShapeDef.setAsBox( (width/2f)/scale, (height/2f)/scale);
  60. // dymShapeDef.setAsBox( (width/2f), (height/2f));
  61. if (density != 0.0f){
  62. dymShapeDef.density = density;
  63. dymShapeDef.friction = friction;
  64. dymShapeDef.restitution = restitution;
  65. }
  66. this.polyDefB4CreationCallback(dymShapeDef); //FIXME TEST
  67. body.createShape(dymShapeDef);
  68. body.setMassFromShapes();
  69. //TEST
  70. // theBody.setBullet(true);
  71. this.setPositionGlobal(scaledPos);
  72. body.setUserData(this);
  73. this.setUserData("box2d", body);
  74. this.setGestureAllowance(ScaleProcessor.class, false);
  75. this.setGestureAllowance(RotateProcessor.class, false);
  76. }
  77. public PhysicsRectangle(PImage texture,
  78. Vector3D pos,
  79. PApplet applet,
  80. Vertex[] physicsVertices,
  81. World world, float density, float friction, float restitution, float scale
  82. ) {
  83. super(applet, texture);
  84. this.angle = 0;
  85. this.drawBounds = false;
  86. this.world = world;
  87. this.density = density;
  88. this.friction = friction;
  89. this.restituion = restitution;
  90. this.setGestureAllowance(ScaleProcessor.class, false);
  91. this.setGestureAllowance(RotateProcessor.class, false);
  92. //Scale shape vertices
  93. // this.setGeometryInfo(new GeometryInfo(applet, Vertex.scaleVectorArray(this.getGeometryInfo().getVertices(), Vector3D.ZERO_VECTOR, 1f/scale, 1f/scale, 1)));
  94. // this.setGeometryInfo(new GeometryInfo(applet, PhysicsHelper.scaleDown(this.getGeometryInfo().getVertices(), scale)));
  95. this.setGeometryInfo(new GeometryInfo(applet, PhysicsHelper.scaleDown(Vertex.getDeepVertexArrayCopy(this.getGeometryInfo().getVertices()), scale)));
  96. //Scale physics vertics
  97. // Vertex.scaleVectorArray(bodyVerts, Vector3D.ZERO_VECTOR, 1f/scale, 1f/scale, 1);
  98. PhysicsHelper.scaleDown(physicsVertices, scale);
  99. Vector3D scaledPos = PhysicsHelper.scaleDown(pos.getCopy(), scale);
  100. //Scale position
  101. // pos.scaleLocal(1f/scale); //FIXME REALLY?
  102. // PhysicsHelper.scaleDown(pos, scale);
  103. this.setGestureAllowance(ScaleProcessor.class, false);
  104. this.setGestureAllowance(RotateProcessor.class, false);
  105. //Temporarily move the mesh so that we know where the calculated center of the body
  106. //would be (the body takes the body.position as the center reference instead of a calculated center)
  107. // //FIXME welchen centerpoint nehmen? -> kommt auch drauf an ob shape schon auf canvas war!?
  108. //We have to do this because the anchor point ("position") of the pyhsics shape is the body.position
  109. //but the anchor point of our shapes is the point returned from getCenterpoint..()
  110. this.translate(scaledPos);
  111. Vector3D realBodyCenter = this.getCenterPointGlobal(); //FIXME geht nur if detached from world //rename futurebodycenter?
  112. //Reset position
  113. this.translate(scaledPos.getScaled(-1));
  114. //Now get the position where the global center will be after setting the shape at the desired position
  115. this.setPositionGlobal(scaledPos);
  116. Vector3D meshCenterAtPosition = this.getCenterPointGlobal();
  117. //Compute the distance we would have to move the vertices for the body creation
  118. //so that the body.position(center) is at the same position as our mesh center
  119. Vector3D realBodyCenterToMeshCenter = meshCenterAtPosition.getSubtracted(realBodyCenter);
  120. //System.out.println("Diff:" + realBodyCenterToMeshCenter);
  121. //FIXME TEST Needed for level saving the local vertices at the right position
  122. this.setUserData("realBodyCenterToMeshCenter", realBodyCenterToMeshCenter);
  123. //Move the vertices so the body position is at the center of the shape
  124. Vertex.translateVectorArray(physicsVertices, realBodyCenterToMeshCenter);
  125. //Create vertex structure for creation of decomposition polygon (use the translated vertices)
  126. float xArr[] = new float[physicsVertices.length];
  127. float yArr[] = new float[physicsVertices.length];
  128. for (int i = 0; i < physicsVertices.length; i++) {
  129. Vertex v = physicsVertices[i];
  130. xArr[i] = v.x;
  131. yArr[i] = v.y;
  132. }
  133. //Create a polygon too see if its simple and eventually decompose it
  134. org.jbox2d.util.nonconvex.Polygon myPoly = new org.jbox2d.util.nonconvex.Polygon(xArr, yArr);
  135. //System.out.println("Polygon is simple! -> Using convex decomposition for physics shape and glu triangulated mesh for display!");
  136. PolygonDef pd = new PolygonDef();
  137. if (density != 0.0f){
  138. pd.density = density;
  139. pd.friction = friction;
  140. pd.restitution = restituion;
  141. }
  142. //Create polygon body
  143. BodyDef dymBodyDef = new BodyDef();
  144. dymBodyDef.position = new Vec2(scaledPos.x, scaledPos.y);
  145. this.bodyDefB4CreationCallback(dymBodyDef);
  146. this.body = world.createBody(dymBodyDef);
  147. this.polyDefB4CreationCallback(pd); //FIXME TEST
  148. int success = org.jbox2d.util.nonconvex.Polygon.decomposeConvexAndAddTo(myPoly, body, pd);
  149. if (success != -1){
  150. System.out.println("-> Ear clipping SUCCESSFUL -> Using triangulated and polygonized shape for b2d.");
  151. body.setMassFromShapes();
  152. body.setUserData(this);
  153. this.setUserData("box2d", body);
  154. //Performance hit! but prevents object from sticking to another sometimes
  155. // theBody.setBullet(true);
  156. }else{
  157. System.out.println("-> Ear clipping had an ERROR - trying again by triangulating shape for b2d with GLU-Triangulator");
  158. GluTrianglulator triangulator = new GluTrianglulator(applet);
  159. List<Vertex> physicsTris = triangulator.tesselate(physicsVertices, GLU.GLU_TESS_WINDING_NONZERO);
  160. Vertex[] triangulatedBodyVerts = physicsTris.toArray(new Vertex[physicsTris.size()]);
  161. //System.out.println("GLU tris created: " + triangulatedBodyVerts.length);
  162. //Cap the max triangles - dont use anymore triangles for the physics body..
  163. int cap = 400;
  164. if (triangulatedBodyVerts.length > cap){
  165. //System.err.println("OVER cap! -> capping!");
  166. Vertex[] tmp = new Vertex[cap];
  167. System.arraycopy(triangulatedBodyVerts, 0, tmp, 0, cap);
  168. triangulatedBodyVerts = tmp;
  169. }
  170. //Create polygon body
  171. world.destroyBody(body);
  172. dymBodyDef = new BodyDef();
  173. dymBodyDef.position = new Vec2(scaledPos.x, scaledPos.y);
  174. this.bodyDefB4CreationCallback(dymBodyDef);
  175. body = world.createBody(dymBodyDef);
  176. for (int i = 0; i < triangulatedBodyVerts.length/3; i++) {
  177. //Create polygon definition
  178. PolygonDef polyDef = new PolygonDef();
  179. if (density != 0.0f){
  180. polyDef.density = density;
  181. polyDef.friction = friction;
  182. polyDef.restitution = restituion;
  183. }
  184. //Add triangle vertices
  185. Vertex vertex1 = triangulatedBodyVerts[i*3];
  186. Vertex vertex2 = triangulatedBodyVerts[i*3+1];
  187. Vertex vertex3 = triangulatedBodyVerts[i*3+2];
  188. polyDef.addVertex(new Vec2(vertex1.x, vertex1.y));
  189. polyDef.addVertex(new Vec2(vertex2.x, vertex2.y));
  190. polyDef.addVertex(new Vec2(vertex3.x, vertex3.y));
  191. this.polyDefB4CreationCallback(pd); //FIXME TEST
  192. //Add poly to body
  193. body.createShape(polyDef);
  194. }
  195. body.setMassFromShapes();
  196. //performance hit!?
  197. //theBody.setBullet(true);
  198. body.setUserData(this);
  199. this.setUserData("box2d", body);
  200. triangulator.deleteTess();
  201. }
  202. }
  203. public void setPhysicsVertices(Vertex[] bodyVerts,
  204. Vector3D pos,
  205. float scale
  206. ){
  207. if (this.body != null && this.world != null){
  208. world.destroyBody(this.body);
  209. }
  210. //Scale physics vertics
  211. // Vertex.scaleVectorArray(bodyVerts, Vector3D.ZERO_VECTOR, 1f/scale, 1f/scale, 1);
  212. PhysicsHelper.scaleDown(bodyVerts, scale);
  213. //Scale position
  214. // pos.scaleLocal(1f/scale); //FIXME REALLY?
  215. // PhysicsHelper.scaleDown(pos, scale);
  216. Vector3D scaledPos = PhysicsHelper.scaleDown(pos.getCopy(), scale);
  217. MTComponent parent = this.getParent();
  218. this.removeFromParent();
  219. //Temporarily move the mesh so that we know where the calculated center of the body
  220. //would be (the body takes the body.position as the center reference instead of a calculated center)
  221. // //FIXME welchen centerpoint nehmen? -> kommt auch drauf an ob shape schon auf canvas war!?
  222. //We have to do this because the anchor point ("position") of the pyhsics shape is the body.position
  223. //but the anchor point of our shapes is the point returned from getCenterpoint..()
  224. this.translate(scaledPos);
  225. Vector3D realBodyCenter = this.getCenterPointGlobal(); //FIXME geht nur if detached from world //rename futurebodycenter?
  226. //Reset position
  227. this.translate(scaledPos.getScaled(-1));
  228. //Now get the position where the global center will be after setting the shape at the desired position
  229. this.setPositionGlobal(scaledPos);
  230. Vector3D meshCenterAtPosition = this.getCenterPointGlobal();
  231. if (parent != null){
  232. parent.addChild(this);//TODO add at same index
  233. }
  234. //Compute the distance we would have to move the vertices for the body creation
  235. //so that the body.position(center) is at the same position as our mesh center
  236. Vector3D realBodyCenterToMeshCenter = meshCenterAtPosition.getSubtracted(realBodyCenter);
  237. //System.out.println("Diff:" + realBodyCenterToMeshCenter);
  238. //Move the vertices so the body position is at the center of the shape
  239. Vertex.translateVectorArray(bodyVerts, realBodyCenterToMeshCenter);
  240. //FIXME TEST
  241. this.setUserData("realBodyCenterToMeshCenter", realBodyCenterToMeshCenter);
  242. //Create vertex structure for creation of decomposition polygon (use the translated vertices)
  243. float xArr[] = new float[bodyVerts.length];
  244. float yArr[] = new float[bodyVerts.length];
  245. for (int i = 0; i < bodyVerts.length; i++) {
  246. Vertex v = bodyVerts[i];
  247. xArr[i] = v.x;
  248. yArr[i] = v.y;
  249. }
  250. //Create a polygon too see if its simple and eventually decompose it
  251. org.jbox2d.util.nonconvex.Polygon myPoly = new org.jbox2d.util.nonconvex.Polygon(xArr, yArr);
  252. //System.out.println("Polygon is simple! -> Using convex decomposition for physics shape and glu triangulated mesh for display!");
  253. PolygonDef pd = new PolygonDef();
  254. if (density != 0.0f){
  255. pd.density = density;
  256. pd.friction = friction;
  257. pd.restitution = restituion;
  258. }
  259. //Create polygon body
  260. BodyDef dymBodyDef = new BodyDef();
  261. dymBodyDef.position = new Vec2(scaledPos.x, scaledPos.y);
  262. this.bodyDefB4CreationCallback(dymBodyDef);
  263. this.body = world.createBody(dymBodyDef);
  264. this.polyDefB4CreationCallback(pd); //FIXME TEST
  265. int success = org.jbox2d.util.nonconvex.Polygon.decomposeConvexAndAddTo(myPoly, body, pd);
  266. if (success != -1){
  267. System.out.println("-> Ear clipping SUCCESSFUL -> Using triangulated and polygonized shape for b2d.");
  268. body.setMassFromShapes();
  269. body.setUserData(this);
  270. this.setUserData("box2d", body);
  271. //Performance hit! but prevents object from sticking to another sometimes
  272. // theBody.setBullet(true);
  273. }else{
  274. System.out.println("-> Ear clipping had an ERROR - trying again by triangulating shape for b2d with GLU-Triangulator");
  275. GluTrianglulator triangulator = new GluTrianglulator(this.getRenderer());
  276. List<Vertex> physicsTris = triangulator.tesselate(bodyVerts, GLU.GLU_TESS_WINDING_NONZERO);
  277. Vertex[] triangulatedBodyVerts = physicsTris.toArray(new Vertex[physicsTris.size()]);
  278. //System.out.println("GLU tris created: " + triangulatedBodyVerts.length);
  279. //Cap the max triangles - dont use anymore triangles for the physics body..
  280. int cap = 400;
  281. if (triangulatedBodyVerts.length > cap){
  282. //System.err.println("OVER cap! -> capping!");
  283. Vertex[] tmp = new Vertex[cap];
  284. System.arraycopy(triangulatedBodyVerts, 0, tmp, 0, cap);
  285. triangulatedBodyVerts = tmp;
  286. }
  287. //Create polygon body
  288. world.destroyBody(body);
  289. dymBodyDef = new BodyDef();
  290. dymBodyDef.position = new Vec2(scaledPos.x, scaledPos.y);
  291. this.bodyDefB4CreationCallback(dymBodyDef);
  292. body = world.createBody(dymBodyDef);
  293. for (int i = 0; i < triangulatedBodyVerts.length/3; i++) {
  294. //Create polygon definition
  295. PolygonDef polyDef = new PolygonDef();
  296. if (density != 0.0f){
  297. polyDef.density = density;
  298. polyDef.friction = friction;
  299. polyDef.restitution = restituion;
  300. }
  301. //Add triangle vertices
  302. Vertex vertex1 = triangulatedBodyVerts[i*3];
  303. Vertex vertex2 = triangulatedBodyVerts[i*3+1];
  304. Vertex vertex3 = triangulatedBodyVerts[i*3+2];
  305. polyDef.addVertex(new Vec2(vertex1.x, vertex1.y));
  306. polyDef.addVertex(new Vec2(vertex2.x, vertex2.y));
  307. polyDef.addVertex(new Vec2(vertex3.x, vertex3.y));
  308. this.polyDefB4CreationCallback(polyDef); //FIXME TEST
  309. //Add poly to body
  310. body.createShape(polyDef);
  311. }
  312. body.setMassFromShapes();
  313. //FIXME TEST - performance hit!?
  314. //theBody.setBullet(true);
  315. body.setUserData(this);
  316. this.setUserData("box2d", body);
  317. triangulator.deleteTess();
  318. }
  319. }
  320. protected void polyDefB4CreationCallback(PolygonDef def){
  321. }
  322. protected void bodyDefB4CreationCallback(BodyDef def){
  323. }
  324. // private Vertex[] physicsVertices;
  325. //
  326. // private Vertex[] getPhysicsVertices(){
  327. // return this.physicsVertices;
  328. // }
  329. //@Override
  330. public void drawComponent(PGraphics g) {
  331. super.drawComponent(g);
  332. if (drawBounds){
  333. IBoundingShape bounds = this.getBounds();
  334. if (bounds instanceof BoundsArbitraryPlanarPolygon){
  335. BoundsArbitraryPlanarPolygon bound = (BoundsArbitraryPlanarPolygon)bounds;
  336. Vector3D[] boundVecs = bound.getVectorsLocal();
  337. // app.noFill();
  338. g.fill(100);
  339. g.stroke(50);
  340. g.beginShape();
  341. for (Vector3D v : boundVecs) {
  342. // app.vertex(v.x*scale, v.y*scale, v.z);
  343. g.vertex(v.x, v.y, v.z);
  344. }
  345. g.endShape();
  346. }
  347. }
  348. }
  349. //@Override
  350. public void rotateZGlobal(Vector3D rotationPoint, float degree) {
  351. angle += degree;
  352. super.rotateZGlobal(rotationPoint, degree);
  353. }
  354. public float getAngle() {
  355. return angle;
  356. }
  357. public void setCenterRotation(float angle){
  358. float degreeAngle = MTApplication.degrees(angle);
  359. float oldAngle = this.getAngle();
  360. float diff = degreeAngle-oldAngle;
  361. //System.out.println("Old angle: " + oldAngle + " new angle:" + degreeAngle + " diff->" + diff);
  362. this.rotateZGlobal(this.getCenterPointGlobal(), diff);
  363. }
  364. //@Override
  365. protected void destroyComponent() {
  366. super.destroyComponent();
  367. boolean exists = false;
  368. for (Body body = world.getBodyList(); body != null; body = body.getNext()) {
  369. if (body.equals(this.body))
  370. exists = true;//Delete later to avoid concurrent modification
  371. }
  372. if (exists)
  373. world.destroyBody(body);
  374. }
  375. public World getWorld() {
  376. return world;
  377. }
  378. public Body getBody() {
  379. return body;
  380. }
  381. public float getDensity() {
  382. return density;
  383. }
  384. public float getFriction() {
  385. return friction;
  386. }
  387. public float getRestituion() {
  388. return restituion;
  389. }
  390. }