Panda3D

collisionParabola.cxx

00001 // Filename: collisionParabola.cxx
00002 // Created by:  drose (11Oct07)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "collisionParabola.h"
00016 #include "collisionEntry.h"
00017 #include "datagram.h"
00018 #include "datagramIterator.h"
00019 #include "bamReader.h"
00020 #include "bamWriter.h"
00021 #include "geom.h"
00022 #include "geomLinestrips.h"
00023 #include "geomVertexWriter.h"
00024 #include "boundingHexahedron.h"
00025 #include "look_at.h"
00026 
00027 PStatCollector CollisionParabola::_volume_pcollector(
00028   "Collision Volumes:CollisionParabola");
00029 PStatCollector CollisionParabola::_test_pcollector(
00030   "Collision Tests:CollisionParabola");
00031 TypeHandle CollisionParabola::_type_handle;
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: CollisionParabola::get_collision_origin
00035 //       Access: Public, Virtual
00036 //  Description: Returns the point in space deemed to be the "origin"
00037 //               of the solid for collision purposes.  The closest
00038 //               intersection point to this origin point is considered
00039 //               to be the most significant.
00040 ////////////////////////////////////////////////////////////////////
00041 LPoint3 CollisionParabola::
00042 get_collision_origin() const {
00043   return _parabola.calc_point(_t1);
00044 }
00045 
00046 ////////////////////////////////////////////////////////////////////
00047 //     Function: CollisionParabola::make_copy
00048 //       Access: Public, Virtual
00049 //  Description:
00050 ////////////////////////////////////////////////////////////////////
00051 CollisionSolid *CollisionParabola::
00052 make_copy() {
00053   return new CollisionParabola(*this);
00054 }
00055 
00056 
00057 ////////////////////////////////////////////////////////////////////
00058 //     Function: CollisionParabola::test_intersection
00059 //       Access: Public, Virtual
00060 //  Description:
00061 ////////////////////////////////////////////////////////////////////
00062 PT(CollisionEntry) CollisionParabola::
00063 test_intersection(const CollisionEntry &entry) const {
00064   return entry.get_into()->test_intersection_from_parabola(entry);
00065 }
00066 
00067 ////////////////////////////////////////////////////////////////////
00068 //     Function: CollisionParabola::xform
00069 //       Access: Public, Virtual
00070 //  Description: Transforms the solid by the indicated matrix.
00071 ////////////////////////////////////////////////////////////////////
00072 void CollisionParabola::
00073 xform(const LMatrix4 &mat) {
00074   _parabola.xform(mat);
00075 
00076   mark_viz_stale();
00077   mark_internal_bounds_stale();
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: CollisionParabola::get_volume_pcollector
00082 //       Access: Public, Virtual
00083 //  Description: Returns a PStatCollector that is used to count the
00084 //               number of bounding volume tests made against a solid
00085 //               of this type in a given frame.
00086 ////////////////////////////////////////////////////////////////////
00087 PStatCollector &CollisionParabola::
00088 get_volume_pcollector() {
00089   return _volume_pcollector;
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: CollisionParabola::get_test_pcollector
00094 //       Access: Public, Virtual
00095 //  Description: Returns a PStatCollector that is used to count the
00096 //               number of intersection tests made against a solid
00097 //               of this type in a given frame.
00098 ////////////////////////////////////////////////////////////////////
00099 PStatCollector &CollisionParabola::
00100 get_test_pcollector() {
00101   return _test_pcollector;
00102 }
00103 
00104 ////////////////////////////////////////////////////////////////////
00105 //     Function: CollisionParabola::output
00106 //       Access: Public, Virtual
00107 //  Description:
00108 ////////////////////////////////////////////////////////////////////
00109 void CollisionParabola::
00110 output(ostream &out) const {
00111   out << _parabola << ", t1 = " << _t1 << ", t2 = " << _t2;
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: CollisionParabola::compute_internal_bounds
00116 //       Access: Protected, Virtual
00117 //  Description:
00118 ////////////////////////////////////////////////////////////////////
00119 PT(BoundingVolume) CollisionParabola::
00120 compute_internal_bounds() const {
00121   LPoint3 p1 = _parabola.calc_point(get_t1());
00122   LPoint3 p2 = _parabola.calc_point(get_t2());
00123   LVector3 pdelta = p2 - p1;
00124 
00125   // If p1 and p2 are sufficiently close, just put a sphere around
00126   // them.
00127   PN_stdfloat d2 = pdelta.length_squared();
00128   if (d2 < collision_parabola_bounds_threshold * collision_parabola_bounds_threshold) {
00129     LPoint3 pmid = (p1 + p2) * 0.5f;
00130     return new BoundingSphere(pmid, csqrt(d2) * 0.5f);
00131   }
00132 
00133   // OK, the more general bounding volume.  We use BoundingHexahedron
00134   // to define a very thin box that roughly bounds the parabola's arc.
00135   // We must use BoundingHexahedron instead of BoundingBox, because
00136   // the box will not be axis-aligned, and might be inflated too large
00137   // if we insist on using the axis-aligned BoundingBox.
00138 
00139   // We first define "parabola space" as a coordinate space such that
00140   // the YZ plane of parabola space corresponds to the plane of the
00141   // parabola.
00142 
00143   // We have to be explicit about the coordinate system--we
00144   // specifically mean CS_zup_right here, to make the YZ plane.
00145 
00146   LMatrix4 from_parabola;
00147   look_at(from_parabola, pdelta, -_parabola.get_a(), CS_zup_right);
00148   from_parabola.set_row(3, p1);
00149 
00150   // The matrix that computes from world space to parabola space is
00151   // the inverse of that which we just computed.
00152   LMatrix4 to_parabola;
00153   to_parabola.invert_from(from_parabola);
00154 
00155   // Now convert the parabola itself into parabola space.
00156   LParabola psp = _parabola;
00157   psp.xform(to_parabola);
00158 
00159   LPoint3 pp2 = psp.calc_point(get_t2());
00160   PN_stdfloat max_y = pp2[1];
00161 
00162   // We compute a few points along the parabola to attempt to get the
00163   // minmax.
00164   PN_stdfloat min_z = 0.0f;
00165   PN_stdfloat max_z = 0.0f;
00166   int num_points = collision_parabola_bounds_sample;
00167   for (int i = 0; i < num_points; ++i) {
00168     double t = (double)(i + 1) / (double)(num_points + 1);
00169     LPoint3 p = psp.calc_point(get_t1() + t * (get_t2() - get_t1()));
00170     min_z = min(min_z, p[2]);
00171     max_z = max(max_z, p[2]);
00172   }
00173 
00174   // That gives us a simple bounding volume in parabola space.
00175   PT(BoundingHexahedron) volume = 
00176     new BoundingHexahedron(LPoint3(-0.01, max_y, min_z), LPoint3(0.01, max_y, min_z),
00177                            LPoint3(0.01, max_y, max_z), LPoint3(-0.01, max_y, max_z), 
00178                            LPoint3(-0.01, 0, min_z), LPoint3(0.01, 0, min_z), 
00179                            LPoint3(0.01, 0, max_z), LPoint3(-0.01, 0, max_z));
00180   // And convert that back into real space.
00181   volume->xform(from_parabola);
00182   return volume.p();
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: CollisionParabola::fill_viz_geom
00187 //       Access: Protected, Virtual
00188 //  Description: Fills the _viz_geom GeomNode up with Geoms suitable
00189 //               for rendering this solid.
00190 ////////////////////////////////////////////////////////////////////
00191 void CollisionParabola::
00192 fill_viz_geom() {
00193   if (collide_cat.is_debug()) {
00194     collide_cat.debug()
00195       << "Recomputing viz for " << *this << "\n";
00196   }
00197 
00198   static const int num_points = 100;
00199 
00200   PT(GeomVertexData) vdata = new GeomVertexData
00201     ("collision", GeomVertexFormat::get_v3cp(),
00202      Geom::UH_static);
00203   GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00204   GeomVertexWriter color(vdata, InternalName::get_color());
00205   
00206   for (int i = 0; i < num_points; i++) {
00207     double t = ((double)i / (double)num_points);
00208     vertex.add_data3(_parabola.calc_point(_t1 + t * (_t2 - _t1)));
00209     
00210     color.add_data4(LColor(1.0f, 1.0f, 1.0f, 0.0f) +
00211                      t * LColor(0.0f, 0.0f, 0.0f, 1.0f));
00212   }
00213 
00214   PT(GeomLinestrips) line = new GeomLinestrips(Geom::UH_static);
00215   line->add_next_vertices(num_points);
00216   line->close_primitive();
00217   
00218   PT(Geom) geom = new Geom(vdata);
00219   geom->add_primitive(line);
00220   
00221   _viz_geom->add_geom(geom, get_other_viz_state());
00222   _bounds_viz_geom->add_geom(geom, get_other_bounds_viz_state());
00223 }
00224 
00225 ////////////////////////////////////////////////////////////////////
00226 //     Function: CollisionParabola::register_with_read_factory
00227 //       Access: Public, Static
00228 //  Description: Factory method to generate a CollisionParabola object
00229 ////////////////////////////////////////////////////////////////////
00230 void CollisionParabola::
00231 register_with_read_factory() {
00232   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: CollisionParabola::write_datagram
00237 //       Access: Public
00238 //  Description: Function to write the important information in
00239 //               the particular object to a Datagram
00240 ////////////////////////////////////////////////////////////////////
00241 void CollisionParabola::
00242 write_datagram(BamWriter *manager, Datagram &me) {
00243   CollisionSolid::write_datagram(manager, me);
00244   _parabola.write_datagram(me);
00245   me.add_stdfloat(_t1);
00246   me.add_stdfloat(_t2);
00247 }
00248 
00249 ////////////////////////////////////////////////////////////////////
00250 //     Function: CollisionParabola::make_from_bam
00251 //       Access: Protected
00252 //  Description: Factory method to generate a CollisionParabola object
00253 ////////////////////////////////////////////////////////////////////
00254 TypedWritable *CollisionParabola::
00255 make_from_bam(const FactoryParams &params) {
00256   CollisionParabola *me = new CollisionParabola;
00257   DatagramIterator scan;
00258   BamReader *manager;
00259 
00260   parse_params(params, scan, manager);
00261   me->fillin(scan, manager);
00262   return me;
00263 }
00264 
00265 ////////////////////////////////////////////////////////////////////
00266 //     Function: CollisionParabola::fillin
00267 //       Access: Protected
00268 //  Description: Function that reads out of the datagram (or asks
00269 //               manager to read) all of the data that is needed to
00270 //               re-create this object and stores it in the appropiate
00271 //               place
00272 ////////////////////////////////////////////////////////////////////
00273 void CollisionParabola::
00274 fillin(DatagramIterator& scan, BamReader* manager) {
00275   CollisionSolid::fillin(scan, manager);
00276   _parabola.read_datagram(scan);
00277   _t1 = scan.get_stdfloat();
00278   _t2 = scan.get_stdfloat();
00279 }
 All Classes Functions Variables Enumerations