cullableObject.cxx 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424
  1. // Filename: cullableObject.cxx
  2. // Created by: drose (04Mar02)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "cullableObject.h"
  19. #include "textureAttrib.h"
  20. #include "renderState.h"
  21. #include "clockObject.h"
  22. #include "cullTraverser.h"
  23. #include "sceneSetup.h"
  24. #include "lens.h"
  25. #include "pStatTimer.h"
  26. #include "qpgeomVertexWriter.h"
  27. #include "qpgeomVertexReader.h"
  28. #include "qpgeomTriangles.h"
  29. PStatCollector CullableObject::_munge_points_pcollector("Cull:Munge:Points");
  30. CullableObject *CullableObject::_deleted_chain = (CullableObject *)NULL;
  31. int CullableObject::_num_ever_allocated = 0;
  32. TypeHandle CullableObject::_type_handle;
  33. ////////////////////////////////////////////////////////////////////
  34. // Function: CullableObject::munge_geom
  35. // Access: Public
  36. // Description: Uses the indicated GeomMunger to transform the geom
  37. // and/or its vertices.
  38. ////////////////////////////////////////////////////////////////////
  39. void CullableObject::
  40. munge_geom(GraphicsStateGuardianBase *gsg,
  41. const qpGeomMunger *munger, const CullTraverser *traverser) {
  42. if (_geom != (Geom *)NULL) {
  43. // Temporary test and dcast until the experimental Geom rewrite
  44. // becomes the actual Geom rewrite.
  45. if (_geom->is_of_type(qpGeom::get_class_type())) {
  46. _munger = munger;
  47. CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
  48. _munged_data = qpgeom->get_vertex_data();
  49. int geom_rendering = _state->get_geom_rendering(qpgeom->get_geom_rendering());
  50. GraphicsStateGuardianBase *gsg = traverser->get_gsg();
  51. int gsg_bits = gsg->get_supported_geom_rendering();
  52. if (!hardware_point_sprites) {
  53. // If support for hardware point sprites or perspective-scaled
  54. // points is disabled, we don't allow the GSG to tell us it
  55. // supports them.
  56. gsg_bits &= ~(qpGeom::GR_point_perspective | qpGeom::GR_point_sprite);
  57. }
  58. int unsupported_bits = geom_rendering & ~gsg_bits;
  59. if ((unsupported_bits & qpGeom::GR_point_bits) != 0) {
  60. // The GSG doesn't support rendering these fancy points
  61. // directly; we have to render them in software instead.
  62. // Munge them into quads. This will replace the _geom and
  63. // _munged_data, and might also replace _state.
  64. munge_points_to_quads(traverser);
  65. qpgeom = DCAST(qpGeom, _geom);
  66. }
  67. // Now invoke the munger to ensure the resulting geometry is in
  68. // a GSG-friendly form.
  69. qpgeom->munge_geom(munger, qpgeom, _munged_data);
  70. CPT(qpGeomVertexData) animated_vertices =
  71. _munged_data->animate_vertices_cull();
  72. #ifndef NDEBUG
  73. if (show_cpu_animation && animated_vertices != _munged_data) {
  74. // These vertices were CPU-animated, so flash them.
  75. static const double flash_rate = 1.0; // 1 state change per second
  76. int cycle = (int)(ClockObject::get_global_clock()->get_frame_time() * flash_rate);
  77. if ((cycle & 1) == 0) {
  78. static Colorf flash_color(0.8f, 0.2f, 0.2f, 1.0f);
  79. if (animated_vertices->has_color()) {
  80. animated_vertices = animated_vertices->set_color(flash_color);
  81. } else {
  82. // We have to add a color column, which means we have to
  83. // re-munge.
  84. animated_vertices = animated_vertices->set_color
  85. (flash_color, 1, qpGeom::NT_packed_dabc, qpGeom::C_color);
  86. animated_vertices = munger->munge_data(animated_vertices);
  87. }
  88. _state = _state->remove_attrib(TextureAttrib::get_class_type());
  89. }
  90. }
  91. #endif
  92. _munged_data = animated_vertices;
  93. _geom = qpgeom;
  94. }
  95. }
  96. if (_next != (CullableObject *)NULL) {
  97. if (_next->_state != (RenderState *)NULL) {
  98. _next->munge_geom(gsg, gsg->get_geom_munger(_next->_state), traverser);
  99. } else {
  100. _next->munge_geom(gsg, munger, traverser);
  101. }
  102. }
  103. }
  104. ////////////////////////////////////////////////////////////////////
  105. // Function: CullableObject::Destructor
  106. // Access: Public
  107. // Description: Automatically deletes the whole chain of these things.
  108. ////////////////////////////////////////////////////////////////////
  109. CullableObject::
  110. ~CullableObject() {
  111. if (_next != (CullableObject *)NULL) {
  112. delete _next;
  113. }
  114. }
  115. ////////////////////////////////////////////////////////////////////
  116. // Function: CullableObject::output
  117. // Access: Public
  118. // Description:
  119. ////////////////////////////////////////////////////////////////////
  120. void CullableObject::
  121. output(ostream &out) const {
  122. if (_geom != (Geom *)NULL) {
  123. out << *_geom;
  124. } else {
  125. out << "(null)";
  126. }
  127. }
  128. ////////////////////////////////////////////////////////////////////
  129. // Function: CullableObject::munge_points_to_quads
  130. // Access: Private
  131. // Description: Converts a table of points to quads for rendering on
  132. // systems that don't support fancy points.
  133. //
  134. // This may replace _geom, _munged_data, and _state.
  135. ////////////////////////////////////////////////////////////////////
  136. void CullableObject::
  137. munge_points_to_quads(const CullTraverser *traverser) {
  138. PStatTimer timer(_munge_points_pcollector);
  139. GraphicsStateGuardianBase *gsg = traverser->get_gsg();
  140. CPT(qpGeom) qpgeom = DCAST(qpGeom, _geom);
  141. qpGeomVertexReader vertex(_munged_data, InternalName::get_vertex());
  142. qpGeomVertexReader normal(_munged_data, InternalName::get_normal());
  143. qpGeomVertexReader color(_munged_data, InternalName::get_color());
  144. qpGeomVertexReader texcoord(_munged_data, InternalName::get_texcoord());
  145. qpGeomVertexReader rotate(_munged_data, InternalName::get_rotate());
  146. qpGeomVertexReader size(_munged_data, InternalName::get_size());
  147. qpGeomVertexReader aspect_ratio(_munged_data, InternalName::get_aspect_ratio());
  148. bool has_normal = (normal.has_column());
  149. bool has_color = (color.has_column());
  150. bool has_texcoord = (texcoord.has_column());
  151. bool has_rotate = (rotate.has_column());
  152. bool has_size = (size.has_column());
  153. bool has_aspect_ratio = (aspect_ratio.has_column());
  154. bool sprite_texcoord = false;
  155. const TexGenAttrib *tex_gen = _state->get_tex_gen();
  156. if (tex_gen != (TexGenAttrib *)NULL) {
  157. if (tex_gen->get_mode(TextureStage::get_default()) == TexGenAttrib::M_point_sprite) {
  158. sprite_texcoord = true;
  159. // Turn off the TexGenAttrib, since we don't want it now.
  160. _state = _state->add_attrib(tex_gen->remove_stage(TextureStage::get_default()));
  161. }
  162. }
  163. PT(qpGeomVertexArrayFormat) new_array_format =
  164. new qpGeomVertexArrayFormat(InternalName::get_vertex(), 4,
  165. qpGeom::NT_float32,
  166. qpGeom::C_clip_point);
  167. if (has_normal) {
  168. const qpGeomVertexColumn *c = normal.get_column();
  169. new_array_format->add_column
  170. (InternalName::get_normal(), c->get_num_components(),
  171. c->get_numeric_type(), c->get_contents());
  172. }
  173. if (has_color) {
  174. const qpGeomVertexColumn *c = color.get_column();
  175. new_array_format->add_column
  176. (InternalName::get_color(), c->get_num_components(),
  177. c->get_numeric_type(), c->get_contents());
  178. }
  179. if (sprite_texcoord) {
  180. new_array_format->add_column
  181. (InternalName::get_texcoord(), 2,
  182. qpGeom::NT_float32,
  183. qpGeom::C_texcoord);
  184. } else if (has_texcoord) {
  185. const qpGeomVertexColumn *c = texcoord.get_column();
  186. new_array_format->add_column
  187. (InternalName::get_texcoord(), c->get_num_components(),
  188. c->get_numeric_type(), c->get_contents());
  189. }
  190. CPT(qpGeomVertexFormat) new_format =
  191. qpGeomVertexFormat::register_format(new_array_format);
  192. PT(qpGeomVertexData) new_data = new qpGeomVertexData
  193. (_munged_data->get_name(), new_format, qpGeom::UH_client);
  194. qpGeomVertexWriter new_vertex(new_data, InternalName::get_vertex());
  195. qpGeomVertexWriter new_normal(new_data, InternalName::get_normal());
  196. qpGeomVertexWriter new_color(new_data, InternalName::get_color());
  197. qpGeomVertexWriter new_texcoord(new_data, InternalName::get_texcoord());
  198. int new_vi = 0;
  199. PT(qpGeom) new_geom = new qpGeom();
  200. new_geom->set_vertex_data(new_data);
  201. const LMatrix4f &modelview = _transform->get_mat();
  202. SceneSetup *scene = traverser->get_scene();
  203. const Lens *lens = scene->get_lens();
  204. const LMatrix4f &lens_mat = lens->get_projection_mat();
  205. LMatrix4f projection =
  206. LMatrix4f::convert_mat(gsg->get_internal_coordinate_system(),
  207. lens->get_coordinate_system()) *
  208. lens_mat;
  209. LMatrix4f render_transform;
  210. if (has_normal) {
  211. render_transform = modelview * projection;
  212. }
  213. int viewport_width = scene->get_viewport_width();
  214. int viewport_height = scene->get_viewport_height();
  215. float point_size = 1.0f;
  216. bool perspective = false;
  217. const RenderModeAttrib *render_mode = _state->get_render_mode();
  218. if (render_mode != (RenderModeAttrib *)NULL) {
  219. point_size = render_mode->get_thickness();
  220. perspective = render_mode->get_perspective();
  221. if (render_mode->get_mode() != RenderModeAttrib::M_filled) {
  222. // Be sure to turn on polygon render mode, since we're actually
  223. // rendering polygons, not points any more.
  224. _state = _state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled));
  225. }
  226. }
  227. // Replace each primitive in the Geom (it's presumably a GeomPoints
  228. // primitive, although it might be some other kind of primitive if
  229. // we got here because RenderModeAttrib::M_point is enabled) with a
  230. // new primitive that replaces each vertex with a quad of the
  231. // appropriate scale and orientation.
  232. // BUG: if we're rendering polygons in M_point mode with a
  233. // CullFaceAttrib in effect, we won't actually apply the
  234. // CullFaceAttrib but will always render all of the vertices of the
  235. // polygons. This is certainly a bug, but in order to fix it we'd
  236. // have to do the face culling ourselves--not sure if it's worth it.
  237. int num_primitives = qpgeom->get_num_primitives();
  238. for (int pi = 0; pi < num_primitives; ++pi) {
  239. const qpGeomPrimitive *primitive = qpgeom->get_primitive(pi);
  240. // We must first convert all of the points to eye space.
  241. int num_points = primitive->get_max_vertex() + 1;
  242. int num_vertices = primitive->get_num_vertices();
  243. PointData *points = (PointData *)alloca(num_points * sizeof(PointData));
  244. unsigned int *vertices = (unsigned int *)alloca(num_vertices * sizeof(unsigned int));
  245. unsigned int *vertices_end = vertices + num_vertices;
  246. if (primitive->is_indexed()) {
  247. qpGeomVertexReader index(primitive->get_vertices(), 0);
  248. for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
  249. // Get the point in eye-space coordinates.
  250. unsigned int v = index.get_data1i();
  251. nassertv(v < (unsigned int)num_points);
  252. (*vi) = v;
  253. vertex.set_row(v);
  254. points[v]._eye = modelview.xform_point(vertex.get_data3f());
  255. points[v]._dist = gsg->compute_distance_to(points[v]._eye);
  256. }
  257. } else {
  258. // Nonindexed case.
  259. unsigned int first_vertex = primitive->get_first_vertex();
  260. for (int i = 0; i < num_vertices; ++i) {
  261. unsigned int v = i + first_vertex;
  262. nassertv(v < (unsigned int)num_points);
  263. vertices[i] = v;
  264. vertex.set_row(i + first_vertex);
  265. points[v]._eye = modelview.xform_point(vertex.get_data3f());
  266. points[v]._dist = gsg->compute_distance_to(points[v]._eye);
  267. }
  268. }
  269. // Now sort the points in order from back-to-front so they will
  270. // render properly with transparency, at least with each other.
  271. sort(vertices, vertices_end, SortPoints(points));
  272. // Go through the points, now in sorted order, and generate a pair
  273. // of triangles for each one. We generate indexed triangles
  274. // instead of two-triangle strips, since this seems to be
  275. // generally faster on PC hardware (otherwise, we'd have to nearly
  276. // double the vertices to stitch all the little triangle strips
  277. // together).
  278. PT(qpGeomPrimitive) new_primitive = new qpGeomTriangles(qpGeom::UH_client);
  279. for (unsigned int *vi = vertices; vi != vertices_end; ++vi) {
  280. // The point in eye coordinates.
  281. const LPoint3f &eye = points[*vi]._eye;
  282. // The point in clip coordinates.
  283. LPoint4f p4 = LPoint4f(eye[0], eye[1], eye[2], 1.0f) * projection;
  284. if (has_size) {
  285. size.set_row(*vi);
  286. point_size = size.get_data1f();
  287. }
  288. float scale_y = point_size;
  289. if (perspective) {
  290. // Perspective-sized points. Here point_size is a width in 3-d
  291. // units. To arrange that, we need to figure out the appropriate
  292. // scaling factor based on the current viewport and projection
  293. // matrix.
  294. LVector3f height(0.0f, point_size, 1.0f);
  295. height = height * projection;
  296. scale_y = height[1] * viewport_height;
  297. // We should then divide the radius by the distance from the
  298. // camera plane, to emulate the glPointParameters() behavior.
  299. scale_y /= gsg->compute_distance_to(eye);
  300. }
  301. // Also factor in the homogeneous scale for being in clip
  302. // coordinates still.
  303. scale_y *= p4[3];
  304. float scale_x = scale_y;
  305. if (has_aspect_ratio) {
  306. aspect_ratio.set_row(*vi);
  307. scale_x *= aspect_ratio.get_data1f();
  308. }
  309. // Define the first two corners based on the scales in X and Y.
  310. LPoint2f c0(scale_x, scale_y);
  311. LPoint2f c1(-scale_x, scale_y);
  312. if (has_rotate) {
  313. // If we have a rotate factor, apply it to those two corners.
  314. rotate.set_row(*vi);
  315. float r = rotate.get_data1f();
  316. LMatrix3f mat = LMatrix3f::rotate_mat(r);
  317. c0 = c0 * mat;
  318. c1 = c1 * mat;
  319. }
  320. // Finally, scale the corners in their newly-rotated position,
  321. // to compensate for the aspect ratio of the viewport.
  322. float rx = 1.0f / viewport_width;
  323. float ry = 1.0f / viewport_height;
  324. c0.set(c0[0] * rx, c0[1] * ry);
  325. c1.set(c1[0] * rx, c1[1] * ry);
  326. new_vertex.add_data4f(p4[0] + c0[0], p4[1] + c0[1], p4[2], p4[3]);
  327. new_vertex.add_data4f(p4[0] + c1[0], p4[1] + c1[1], p4[2], p4[3]);
  328. new_vertex.add_data4f(p4[0] - c1[0], p4[1] - c1[1], p4[2], p4[3]);
  329. new_vertex.add_data4f(p4[0] - c0[0], p4[1] - c0[1], p4[2], p4[3]);
  330. if (has_normal) {
  331. normal.set_row(*vi);
  332. Normalf c = render_transform.xform_vec(normal.get_data3f());
  333. new_normal.add_data3f(c);
  334. new_normal.add_data3f(c);
  335. new_normal.add_data3f(c);
  336. new_normal.add_data3f(c);
  337. }
  338. if (has_color) {
  339. color.set_row(*vi);
  340. const Colorf &c = color.get_data4f();
  341. new_color.add_data4f(c);
  342. new_color.add_data4f(c);
  343. new_color.add_data4f(c);
  344. new_color.add_data4f(c);
  345. }
  346. if (sprite_texcoord) {
  347. new_texcoord.add_data2f(1.0f, 0.0f);
  348. new_texcoord.add_data2f(0.0f, 0.0f);
  349. new_texcoord.add_data2f(1.0f, 1.0f);
  350. new_texcoord.add_data2f(0.0f, 1.0f);
  351. } else if (has_texcoord) {
  352. texcoord.set_row(*vi);
  353. const LVecBase4f &c = texcoord.get_data4f();
  354. new_texcoord.add_data4f(c);
  355. new_texcoord.add_data4f(c);
  356. new_texcoord.add_data4f(c);
  357. new_texcoord.add_data4f(c);
  358. }
  359. new_primitive->add_vertex(new_vi);
  360. new_primitive->add_vertex(new_vi + 1);
  361. new_primitive->add_vertex(new_vi + 2);
  362. new_primitive->close_primitive();
  363. new_primitive->add_vertex(new_vi + 2);
  364. new_primitive->add_vertex(new_vi + 1);
  365. new_primitive->add_vertex(new_vi + 3);
  366. new_primitive->close_primitive();
  367. new_vi += 4;
  368. }
  369. new_geom->add_primitive(new_primitive);
  370. }
  371. _geom = new_geom.p();
  372. _munged_data = new_data;
  373. }