|
@@ -22,6 +22,7 @@
|
|
|
#include "cullableObject.h"
|
|
#include "cullableObject.h"
|
|
|
#include "cullHandler.h"
|
|
#include "cullHandler.h"
|
|
|
#include "geomLinestrip.h"
|
|
#include "geomLinestrip.h"
|
|
|
|
|
+#include "geomTristrip.h"
|
|
|
#include "bamWriter.h"
|
|
#include "bamWriter.h"
|
|
|
#include "bamReader.h"
|
|
#include "bamReader.h"
|
|
|
#include "datagram.h"
|
|
#include "datagram.h"
|
|
@@ -149,35 +150,21 @@ has_cull_callback() const {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
bool RopeNode::
|
|
bool RopeNode::
|
|
|
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|
|
- // Create a new linestrip on-the-fly to render the rope.
|
|
|
|
|
- int num_verts = get_num_segs() + 1;
|
|
|
|
|
- if (num_verts >= 2) {
|
|
|
|
|
- PTA_Vertexf verts;
|
|
|
|
|
- PTA_int lengths;
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // Create some geometry on-the-fly to render the rope.
|
|
|
|
|
+ if (get_num_segs() > 0) {
|
|
|
NurbsCurveEvaluator *curve = get_curve();
|
|
NurbsCurveEvaluator *curve = get_curve();
|
|
|
PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path());
|
|
PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path());
|
|
|
|
|
|
|
|
- int num_segments = result->get_num_segments();
|
|
|
|
|
- if (num_segments > 0) {
|
|
|
|
|
- for (int segment = 0; segment < num_segments; segment++) {
|
|
|
|
|
- for (int i = 0; i < num_verts; i++) {
|
|
|
|
|
- float t = (float)i / (float)(num_verts - 1);
|
|
|
|
|
- LPoint3f point;
|
|
|
|
|
- result->eval_segment_point(segment, t, point);
|
|
|
|
|
- verts.push_back(point);
|
|
|
|
|
- }
|
|
|
|
|
- lengths.push_back(num_verts);
|
|
|
|
|
|
|
+ if (result->get_num_segments() > 0) {
|
|
|
|
|
+ switch (get_render_mode()) {
|
|
|
|
|
+ case RM_thread:
|
|
|
|
|
+ render_thread(trav, data, result);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case RM_billboard:
|
|
|
|
|
+ render_billboard(trav, data, result);
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- PT(Geom) geom = new GeomLinestrip;
|
|
|
|
|
- geom->set_num_prims(num_segments);
|
|
|
|
|
- geom->set_coords(verts);
|
|
|
|
|
- geom->set_lengths(lengths);
|
|
|
|
|
-
|
|
|
|
|
- CullableObject *object = new CullableObject(geom, data._state,
|
|
|
|
|
- data._render_transform);
|
|
|
|
|
- trav->get_cull_handler()->record_object(object);
|
|
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -245,6 +232,192 @@ recompute_internal_bound() {
|
|
|
return reset_bound(NodePath(this));
|
|
return reset_bound(NodePath(this));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: RopeNode::render_thread
|
|
|
|
|
+// Access: Private
|
|
|
|
|
+// Description: Draws the rope in RM_thread mode. This uses a
|
|
|
|
|
+// GeomLinestrip to draw the rope in the simplest
|
|
|
|
|
+// possible method, generally resulting in a
|
|
|
|
|
+// one-pixel-wide curve.
|
|
|
|
|
+//
|
|
|
|
|
+// In this mode, the thickness parameter represents a
|
|
|
|
|
+// thickness in pixels, and is passed to the linestrip.
|
|
|
|
|
+// However, you should be aware the DirectX does not
|
|
|
|
|
+// support line thickness.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void RopeNode::
|
|
|
|
|
+render_thread(CullTraverser *trav, CullTraverserData &data,
|
|
|
|
|
+ NurbsCurveResult *result) {
|
|
|
|
|
+ PTA_Vertexf verts;
|
|
|
|
|
+ PTA_TexCoordf uvs;
|
|
|
|
|
+ PTA_int lengths;
|
|
|
|
|
+
|
|
|
|
|
+ int num_verts = get_num_segs() + 1;
|
|
|
|
|
+ int num_segments = result->get_num_segments();
|
|
|
|
|
+ for (int segment = 0; segment < num_segments; segment++) {
|
|
|
|
|
+ for (int i = 0; i < num_verts; i++) {
|
|
|
|
|
+ float t = (float)i / (float)(num_verts - 1);
|
|
|
|
|
+ LPoint3f point;
|
|
|
|
|
+ result->eval_segment_point(segment, t, point);
|
|
|
|
|
+ verts.push_back(point);
|
|
|
|
|
+ uvs.push_back(TexCoordf(result->get_segment_t(segment, t), 0.0f));
|
|
|
|
|
+ }
|
|
|
|
|
+ lengths.push_back(num_verts);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ PT(Geom) geom = new GeomLinestrip;
|
|
|
|
|
+ geom->set_num_prims(num_segments);
|
|
|
|
|
+ geom->set_coords(verts);
|
|
|
|
|
+ geom->set_lengths(lengths);
|
|
|
|
|
+
|
|
|
|
|
+ CullableObject *object = new CullableObject(geom, data._state,
|
|
|
|
|
+ data._render_transform);
|
|
|
|
|
+ trav->get_cull_handler()->record_object(object);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+// Function: RopeNode::render_billboard
|
|
|
|
|
+// Access: Private
|
|
|
|
|
+// Description: Draws the rope in RM_billboard mode. This draws a
|
|
|
|
|
+// series of triangle strips oriented to be
|
|
|
|
|
+// perpendicular to the camera plane.
|
|
|
|
|
+//
|
|
|
|
|
+// In this mode, thickness is in spatial units, and
|
|
|
|
|
+// determines the with of the triangle strips.
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
|
|
+void RopeNode::
|
|
|
|
|
+render_billboard(CullTraverser *trav, CullTraverserData &data,
|
|
|
|
|
+ NurbsCurveResult *result) {
|
|
|
|
|
+ const TransformState *net_transform = data._net_transform;
|
|
|
|
|
+ const TransformState *camera_transform = trav->get_camera_transform();
|
|
|
|
|
+
|
|
|
|
|
+ CPT(TransformState) rel_transform =
|
|
|
|
|
+ net_transform->invert_compose(camera_transform);
|
|
|
|
|
+ LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
|
|
|
|
|
+
|
|
|
|
|
+ float thickness = get_thickness();
|
|
|
|
|
+ float radius = thickness * 0.5f;
|
|
|
|
|
+ UVMode uv_mode = get_uv_mode();
|
|
|
|
|
+ LVecBase2f uv_scale = get_uv_scale();
|
|
|
|
|
+
|
|
|
|
|
+ // We can't just build one tristrip per segment. Instead, we should
|
|
|
|
|
+ // build one continuous tristrip for all connected segments, so we
|
|
|
|
|
+ // can stitch them together properly at the seams.
|
|
|
|
|
+
|
|
|
|
|
+ int num_verts = get_num_segs() + 1;
|
|
|
|
|
+ int num_segments = result->get_num_segments();
|
|
|
|
|
+
|
|
|
|
|
+ vector_Vertexf center_verts;
|
|
|
|
|
+ vector_int center_lengths;
|
|
|
|
|
+ vector_float center_t;
|
|
|
|
|
+
|
|
|
|
|
+ LPoint3f point;
|
|
|
|
|
+ int cur_length = 0;
|
|
|
|
|
+ for (int segment = 0; segment < num_segments; segment++) {
|
|
|
|
|
+ LPoint3f first_point;
|
|
|
|
|
+ result->eval_segment_point(segment, 0.0f, first_point);
|
|
|
|
|
+ if (cur_length == 0 || point != first_point) {
|
|
|
|
|
+ // If the first point of this segment is different from the last
|
|
|
|
|
+ // point of the previous segment, end the tristrip and store the
|
|
|
|
|
+ // point.
|
|
|
|
|
+ if (cur_length != 0) {
|
|
|
|
|
+ center_lengths.push_back(cur_length);
|
|
|
|
|
+ }
|
|
|
|
|
+ center_verts.push_back(first_point);
|
|
|
|
|
+ center_t.push_back(result->get_segment_t(segment, 0.0f));
|
|
|
|
|
+ cur_length = 1;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Store all the remaining points in this segment.
|
|
|
|
|
+ for (int i = 1; i < num_verts; i++) {
|
|
|
|
|
+ float t = (float)i / (float)(num_verts - 1);
|
|
|
|
|
+ result->eval_segment_point(segment, t, point);
|
|
|
|
|
+ center_verts.push_back(point);
|
|
|
|
|
+ center_t.push_back(result->get_segment_t(segment, t));
|
|
|
|
|
+ cur_length++;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ if (cur_length != 0) {
|
|
|
|
|
+ center_lengths.push_back(cur_length);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Now we have stored one or more sequences of vertices down the
|
|
|
|
|
+ // center strips. Go back and convert them into actual tristrips.
|
|
|
|
|
+
|
|
|
|
|
+ PTA_Vertexf verts;
|
|
|
|
|
+ PTA_TexCoordf uvs;
|
|
|
|
|
+ PTA_int lengths;
|
|
|
|
|
+
|
|
|
|
|
+ int vi = 0;
|
|
|
|
|
+ int num_prims = 0;
|
|
|
|
|
+ float dist = 0.0f;
|
|
|
|
|
+ for (int i = 0; i < (int)center_lengths.size(); i++) {
|
|
|
|
|
+ int length = center_lengths[i];
|
|
|
|
|
+ for (int j = 0; j < length; j++) {
|
|
|
|
|
+ const Vertexf &point = center_verts[vi + j];
|
|
|
|
|
+ float t = center_t[vi + j];
|
|
|
|
|
+ LVector3f tangent;
|
|
|
|
|
+ // Rather than evaluating the curve for the tangent, we derive
|
|
|
|
|
+ // it from the neighboring points. This gives us better
|
|
|
|
|
+ // behavior at the endpoints, where the tangent might go to
|
|
|
|
|
+ // zero.
|
|
|
|
|
+ if (j == 0) {
|
|
|
|
|
+ tangent = center_verts[vi + j + 1] - point;
|
|
|
|
|
+ } else if (j == length - 1) {
|
|
|
|
|
+ tangent = point - center_verts[vi + j - 1];
|
|
|
|
|
+ } else {
|
|
|
|
|
+ tangent = center_verts[vi + j + 1] - center_verts[vi + j - 1];
|
|
|
|
|
+ }
|
|
|
|
|
+ LVector3f cross = normalize(tangent.cross(camera_vec));
|
|
|
|
|
+ cross *= radius;
|
|
|
|
|
+ verts.push_back(point + cross);
|
|
|
|
|
+ verts.push_back(point - cross);
|
|
|
|
|
+ switch (uv_mode) {
|
|
|
|
|
+ case UV_none:
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case UV_parametric:
|
|
|
|
|
+ uvs.push_back(TexCoordf(t * uv_scale[0], uv_scale[1]));
|
|
|
|
|
+ uvs.push_back(TexCoordf(t * uv_scale[0], 0.0f));
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case UV_distance:
|
|
|
|
|
+ if (j != 0) {
|
|
|
|
|
+ LVector3f vec = point - center_verts[vi + j - 1];
|
|
|
|
|
+ dist += vec.length();
|
|
|
|
|
+ }
|
|
|
|
|
+ uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
|
|
|
|
|
+ uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case UV_distance2:
|
|
|
|
|
+ if (j != 0) {
|
|
|
|
|
+ LVector3f vec = point - center_verts[vi + j - 1];
|
|
|
|
|
+ dist += vec.length_squared();
|
|
|
|
|
+ }
|
|
|
|
|
+ uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
|
|
|
|
|
+ uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ vi += length;
|
|
|
|
|
+ lengths.push_back(length * 2);
|
|
|
|
|
+ num_prims++;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ PT(Geom) geom = new GeomTristrip;
|
|
|
|
|
+ geom->set_num_prims(num_prims);
|
|
|
|
|
+ geom->set_coords(verts);
|
|
|
|
|
+ if (uv_mode != UV_none) {
|
|
|
|
|
+ geom->set_texcoords(uvs, G_PER_VERTEX);
|
|
|
|
|
+ }
|
|
|
|
|
+ geom->set_lengths(lengths);
|
|
|
|
|
+
|
|
|
|
|
+ CullableObject *object = new CullableObject(geom, data._state,
|
|
|
|
|
+ data._render_transform);
|
|
|
|
|
+ trav->get_cull_handler()->record_object(object);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: RopeNode::register_with_read_factory
|
|
// Function: RopeNode::register_with_read_factory
|
|
|
// Access: Public, Static
|
|
// Access: Public, Static
|