Panda3D
|
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 ¶ms) { 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 }