Răsfoiți Sursa

Merge branch 'release/1.10.x'

rdb 3 ani în urmă
părinte
comite
8354e175cf

+ 239 - 292
direct/src/motiontrail/cMotionTrail.cxx

@@ -15,7 +15,16 @@
 #include "cMotionTrail.h"
 #include "renderState.h"
 #include "colorAttrib.h"
+#include "cmath.h"
 
+static PN_stdfloat one_minus_x(PN_stdfloat x) {
+  x = 1.0 - x;
+  if (x < 0.0) {
+    x = 0.0;
+  }
+
+  return x;
+}
 
 TypeHandle CMotionTrail::_type_handle;
 
@@ -23,7 +32,7 @@ TypeHandle CMotionTrail::_type_handle;
  * Constructor
  */
 CMotionTrail::
-CMotionTrail ( ) {
+CMotionTrail() {
 
   _active = true;
   _enable = true;
@@ -39,8 +48,8 @@ CMotionTrail ( ) {
 
   _last_update_time = 0.0f;
 
-  _vertex_list.clear ( );
-  _frame_list.clear ( );
+  _vertex_list.clear();
+  _frame_list.clear();
 
   // parameters
   _color_scale = 1.0;
@@ -69,7 +78,7 @@ CMotionTrail ( ) {
  * Destructor
  */
 CMotionTrail::
-~CMotionTrail ( ) {
+~CMotionTrail() {
 
 }
 
@@ -77,23 +86,23 @@ CMotionTrail::
  * Reset the frame sample history.
  */
 void CMotionTrail::
-reset ( ) {
-  _frame_list.clear ( );
+reset() {
+  _frame_list.clear();
 }
 
 /**
  * Reset the vertex list.
  */
 void CMotionTrail::
-reset_vertex_list ( ) {
-  _vertex_list.clear ( );
+reset_vertex_list() {
+  _vertex_list.clear();
 }
 
 /**
  * Enable/disable the motion trail.
  */
 void CMotionTrail::
-enable (bool enable) {
+enable(bool enable) {
   _enable = enable;
 }
 
@@ -101,7 +110,7 @@ enable (bool enable) {
  * Set the GeomNode.
  */
 void CMotionTrail::
-set_geom_node (GeomNode *geom_node) {
+set_geom_node(GeomNode *geom_node) {
   _geom_node = geom_node;
 }
 
@@ -109,7 +118,7 @@ set_geom_node (GeomNode *geom_node) {
  * Add a vertex.
  */
 void CMotionTrail::
-add_vertex (LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_stdfloat v) {
+add_vertex(LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_stdfloat v) {
 
   CMotionTrailVertex motion_trail_vertex;
 
@@ -118,9 +127,9 @@ add_vertex (LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_std
   motion_trail_vertex._end_color = *end_color;
   motion_trail_vertex._v = v;
 
-  motion_trail_vertex._nurbs_curve_evaluator = new NurbsCurveEvaluator ( );
+  motion_trail_vertex._nurbs_curve_evaluator = new NurbsCurveEvaluator();
 
-  _vertex_list.push_back (motion_trail_vertex);
+  _vertex_list.push_back(motion_trail_vertex);
 }
 
 /**
@@ -143,7 +152,7 @@ add_vertex (LVector4 *vertex, LVector4 *start_color, LVector4 *end_color, PN_std
  * only if nurbs is on.
  */
 void CMotionTrail::
-set_parameters (PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_texture, bool calculate_relative_matrix, bool use_nurbs, PN_stdfloat resolution_distance) {
+set_parameters(PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_texture, bool calculate_relative_matrix, bool use_nurbs, PN_stdfloat resolution_distance) {
 
   _sampling_time = sampling_time;
   _time_window = time_window;
@@ -157,7 +166,7 @@ set_parameters (PN_stdfloat sampling_time, PN_stdfloat time_window, bool use_tex
  * Check if a sample can be submitted.
  */
 int CMotionTrail::
-check_for_update (PN_stdfloat current_time) {
+check_for_update(PN_stdfloat current_time) {
 
   int state;
 
@@ -173,29 +182,28 @@ check_for_update (PN_stdfloat current_time) {
   return state;
 }
 
-PN_stdfloat one_minus_x (PN_stdfloat x) {
-  x = 1.0 - x;
-  if (x < 0.0) {
-    x = 0.0;
-  }
-
-  return x;
+/**
+ *
+ */
+void CMotionTrail::
+begin_geometry() {
+  begin_geometry(0);
 }
 
 /**
  *
  */
 void CMotionTrail::
-begin_geometry ( ) {
-
+begin_geometry(int num_quads) {
+  const int num_vertices = num_quads * 4;
   const GeomVertexFormat *format;
 
   _vertex_index = 0;
   if (_use_texture) {
-    format = GeomVertexFormat::get_v3c4t2 ( );
+    format = GeomVertexFormat::get_v3c4t2();
   }
   else {
-    format = GeomVertexFormat::get_v3c4 ( );
+    format = GeomVertexFormat::get_v3c4();
   }
 
   // Clear the previous writers before we create a new vertex data object--
@@ -205,111 +213,124 @@ begin_geometry ( ) {
   _color_writer.clear();
   _texture_writer.clear();
 
-  _vertex_data = new GeomVertexData ("vertices", format, Geom::UH_static);
-  _vertex_writer = GeomVertexWriter (_vertex_data, "vertex");
-  _color_writer = GeomVertexWriter (_vertex_data, "color");
+  Thread *current_thread = Thread::get_current_thread();
+
+  _vertex_data = new GeomVertexData("vertices", format, Geom::UH_static);
+  _vertex_data->unclean_set_num_rows(num_vertices);
+  _vertex_writer = GeomVertexWriter(_vertex_data, "vertex", current_thread);
+  _color_writer = GeomVertexWriter(_vertex_data, "color", current_thread);
   if (_use_texture) {
-    _texture_writer = GeomVertexWriter (_vertex_data, "texcoord");
+    _texture_writer = GeomVertexWriter(_vertex_data, "texcoord", current_thread);
+  }
+
+  // We know how many triangles we'll be adding, so add them up front.
+  _triangles = new GeomTriangles(Geom::UH_static);
+  if (num_quads * 6 <= 65535) {
+    _triangles->set_index_type(GeomEnums::NT_uint16);
+  } else {
+    _triangles->set_index_type(GeomEnums::NT_uint32);
+  }
+
+  {
+    PT(GeomVertexArrayDataHandle) idx_handle = _triangles->modify_vertices_handle(current_thread);
+    idx_handle->unclean_set_num_rows(num_quads * 6);
+    if (num_quads * 6 <= 65535) {
+      // 16-bit index case.
+      uint16_t *idx_ptr = (uint16_t *)idx_handle->get_write_pointer();
+
+      for (int i = 0; i < num_vertices; i += 4) {
+        *(idx_ptr++) = i + 0;
+        *(idx_ptr++) = i + 1;
+        *(idx_ptr++) = i + 2;
+        *(idx_ptr++) = i + 1;
+        *(idx_ptr++) = i + 3;
+        *(idx_ptr++) = i + 2;
+      }
+    } else {
+      // 32-bit index case.
+      uint32_t *idx_ptr = (uint32_t *)idx_handle->get_write_pointer();
+
+      for (int i = 0; i < num_vertices; i += 4) {
+        *(idx_ptr++) = i + 0;
+        *(idx_ptr++) = i + 1;
+        *(idx_ptr++) = i + 2;
+        *(idx_ptr++) = i + 1;
+        *(idx_ptr++) = i + 3;
+        *(idx_ptr++) = i + 2;
+      }
+    }
   }
 
-  _triangles = new GeomTriangles (Geom::UH_static);
+  // We can compute this value much faster than GeomPrimitive can.
+  _triangles->set_minmax(0, num_vertices - 1, nullptr, nullptr);
 }
 
 /**
  * LVector3 vertex version.
  */
 void CMotionTrail::
-add_geometry_quad (LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3) {
-
-  _vertex_writer.add_data3 (v0);
-  _vertex_writer.add_data3 (v1);
-  _vertex_writer.add_data3 (v2);
-  _vertex_writer.add_data3 (v3);
+add_geometry_quad(LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3) {
+  _vertex_writer.set_data3(v0);
+  _vertex_writer.set_data3(v1);
+  _vertex_writer.set_data3(v2);
+  _vertex_writer.set_data3(v3);
 
-  _color_writer.add_data4 (c0);
-  _color_writer.add_data4 (c1);
-  _color_writer.add_data4 (c2);
-  _color_writer.add_data4 (c3);
+  _color_writer.set_data4(c0);
+  _color_writer.set_data4(c1);
+  _color_writer.set_data4(c2);
+  _color_writer.set_data4(c3);
 
   if (_use_texture) {
-    _texture_writer.add_data2 (t0);
-    _texture_writer.add_data2 (t1);
-    _texture_writer.add_data2 (t2);
-    _texture_writer.add_data2 (t3);
+    _texture_writer.set_data2(t0);
+    _texture_writer.set_data2(t1);
+    _texture_writer.set_data2(t2);
+    _texture_writer.set_data2(t3);
   }
-
-  int vertex_index;
-  vertex_index = _vertex_index;
-
-  _triangles -> add_vertex (vertex_index + 0);
-  _triangles -> add_vertex (vertex_index + 1);
-  _triangles -> add_vertex (vertex_index + 2);
-  _triangles -> close_primitive ( );
-
-  _triangles -> add_vertex (vertex_index + 1);
-  _triangles -> add_vertex (vertex_index + 3);
-  _triangles -> add_vertex (vertex_index + 2);
-  _triangles -> close_primitive ( );
-
-  _vertex_index += 4;
 }
 
 /**
  * LVector4 vertex version.
  */
 void CMotionTrail::
-add_geometry_quad (LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3) {
-
-  _vertex_writer.add_data3 (v0 [0], v0 [1], v0 [2]);
-  _vertex_writer.add_data3 (v1 [0], v1 [1], v1 [2]);
-  _vertex_writer.add_data3 (v2 [0], v2 [1], v2 [2]);
-  _vertex_writer.add_data3 (v3 [0], v3 [1], v3 [2]);
+add_geometry_quad(LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3) {
+  _vertex_writer.set_data3(v0[0], v0[1], v0[2]);
+  _vertex_writer.set_data3(v1[0], v1[1], v1[2]);
+  _vertex_writer.set_data3(v2[0], v2[1], v2[2]);
+  _vertex_writer.set_data3(v3[0], v3[1], v3[2]);
 
-  _color_writer.add_data4 (c0);
-  _color_writer.add_data4 (c1);
-  _color_writer.add_data4 (c2);
-  _color_writer.add_data4 (c3);
+  _color_writer.set_data4(c0);
+  _color_writer.set_data4(c1);
+  _color_writer.set_data4(c2);
+  _color_writer.set_data4(c3);
 
   if (_use_texture) {
-    _texture_writer.add_data2 (t0);
-    _texture_writer.add_data2 (t1);
-    _texture_writer.add_data2 (t2);
-    _texture_writer.add_data2 (t3);
+    _texture_writer.set_data2(t0);
+    _texture_writer.set_data2(t1);
+    _texture_writer.set_data2(t2);
+    _texture_writer.set_data2(t3);
   }
-
-  int vertex_index;
-  vertex_index = _vertex_index;
-
-  _triangles -> add_vertex (vertex_index + 0);
-  _triangles -> add_vertex (vertex_index + 1);
-  _triangles -> add_vertex (vertex_index + 2);
-  _triangles -> close_primitive ( );
-
-  _triangles -> add_vertex (vertex_index + 1);
-  _triangles -> add_vertex (vertex_index + 3);
-  _triangles -> add_vertex (vertex_index + 2);
-  _triangles -> close_primitive ( );
-
-  _vertex_index += 4;
 }
 
 /**
  *
  */
-void CMotionTrail::end_geometry ( ) {
+void CMotionTrail::
+end_geometry() {
   static CPT(RenderState) state;
   if (state == nullptr) {
     state = RenderState::make(ColorAttrib::make_vertex());
   }
 
-  PT(Geom) geometry;
+  _vertex_writer.clear();
+  _color_writer.clear();
+  _texture_writer.clear();
 
-  geometry = new Geom (_vertex_data);
-  geometry -> add_primitive (_triangles);
+  PT(Geom) geometry = new Geom(_vertex_data);
+  geometry->add_primitive(_triangles);
 
   if (_geom_node) {
-    _geom_node -> remove_all_geoms ( );
-    _geom_node -> add_geom (geometry, state);
+    _geom_node->remove_all_geoms();
+    _geom_node->add_geom(geometry, state);
   }
 }
 
@@ -317,33 +338,21 @@ void CMotionTrail::end_geometry ( ) {
  * See class header comments.
  */
 void CMotionTrail::
-update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
-
-  int debug;
-  int total_frames;
-
-  debug = false;
-
-  total_frames = _frame_list.size ( );
-  if (total_frames >= 1) {
-    FrameList::iterator frame_iterator;
-    CMotionTrailFrame motion_trail_frame;
+update_motion_trail(PN_stdfloat current_time, LMatrix4 *transform) {
+  int debug = false;
 
-    frame_iterator = _frame_list.begin ( );
-    motion_trail_frame = *frame_iterator;
-    if (motion_trail_frame._transform == UnalignedLMatrix4(*transform)) {
+  if (!_frame_list.empty()) {
+    if (_frame_list.front()._transform == UnalignedLMatrix4(*transform)) {
       // duplicate transform
       return;
     }
   }
 
-  int total_vertices;
   PN_stdfloat color_scale;
   LMatrix4 start_transform;
   LMatrix4 end_transform;
   LMatrix4 inverse_matrix;
 
-  total_vertices = _vertex_list.size ( );
   color_scale = _color_scale;
   if (_fade) {
     PN_stdfloat elapsed_time;
@@ -364,40 +373,33 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
   _last_update_time = current_time;
 
   // remove expired frames
-  PN_stdfloat minimum_time;
-
-  minimum_time = current_time - _time_window;
-
-  CMotionTrailFrame motion_trail_frame;
+  PN_stdfloat minimum_time = current_time - _time_window;
 
   while (!_frame_list.empty()) {
-    motion_trail_frame = _frame_list.back();
-    if (motion_trail_frame._time >= minimum_time) {
+    if (_frame_list.back()._time >= minimum_time) {
       break;
     }
 
-    _frame_list.pop_back ( );
+    _frame_list.pop_back();
   }
 
   // add new frame to beginning of list
   {
     CMotionTrailFrame motion_trail_frame;
-
     motion_trail_frame._time = current_time;
     motion_trail_frame._transform = *transform;
-
-    _frame_list.push_front(motion_trail_frame);
+    _frame_list.push_front(std::move(motion_trail_frame));
   }
 
   // convert frames and vertices to geometry
-  total_frames = _frame_list.size ( );
+  int total_frames = (int)_frame_list.size();
+  int total_vertices = (int)_vertex_list.size();
 
   if (debug) {
-    printf ("update_motion_trail, total_frames = %d, total_vertices = %d, nurbs = %d, _calculate_relative_matrix = %d \n", total_frames, total_vertices, _use_nurbs, _calculate_relative_matrix);
+    printf("update_motion_trail, total_frames = %d, total_vertices = %d, nurbs = %d, _calculate_relative_matrix = %d \n", total_frames, total_vertices, _use_nurbs, _calculate_relative_matrix);
   }
 
-  if ((total_frames >= 2) && (total_vertices >= 2)) {
-    int total_segments;
+  if (total_frames >= 2 && total_vertices >= 2) {
     PN_stdfloat minimum_time;
     PN_stdfloat delta_time;
     CMotionTrailFrame last_motion_trail_frame;
@@ -406,16 +408,14 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
 
     // convert vertex list to vertex array
     int index = 0;
-    _vertex_array = new CMotionTrailVertex [total_vertices];
-    for (vertex_iterator = _vertex_list.begin ( ); vertex_iterator != _vertex_list.end ( ); vertex_iterator++) {
-      _vertex_array [index] = *vertex_iterator;
-      index++;
+    CMotionTrailVertex *vertex_array = new CMotionTrailVertex[total_vertices];
+    for (vertex_iterator = _vertex_list.begin(); vertex_iterator != _vertex_list.end(); vertex_iterator++) {
+      vertex_array[index] = *vertex_iterator;
+      ++index;
     }
 
-    // begin geometry
-    this -> begin_geometry ( );
-
-    total_segments = total_frames - 1;
+    const int total_segments = total_frames - 1;
+    const int total_vertex_segments = total_vertices - 1;
 
     last_motion_trail_frame = _frame_list.back();
     minimum_time = last_motion_trail_frame._time;
@@ -423,14 +423,11 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
 
     if (_calculate_relative_matrix) {
       inverse_matrix = *transform;
-      inverse_matrix.invert_in_place ( );
+      inverse_matrix.invert_in_place();
     }
 
-    if (_use_nurbs && (total_frames >= 5)) {
-
+    if (_use_nurbs && total_frames >= 5) {
       // nurbs version
-      int total_vertex_segments;
-      PN_stdfloat total_distance;
       LVector3 vector;
       LVector4 v;
       LVector4 v0;
@@ -438,8 +435,7 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
       LVector4 v2;
       LVector4 v3;
 
-      total_vertex_segments = total_vertices - 1;
-      total_distance = 0.0f;
+      PN_stdfloat total_distance = 0.0f;
 
       // reset NurbsCurveEvaluators for each vertex (the starting point for
       // the trail)
@@ -447,33 +443,28 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
         CMotionTrailVertex *motion_trail_vertex;
         PT(NurbsCurveEvaluator) nurbs_curve_evaluator;
 
-        for (index = 0; index < total_vertices; index++) {
-          motion_trail_vertex = &_vertex_array [index];
-          nurbs_curve_evaluator = motion_trail_vertex -> _nurbs_curve_evaluator;
-          nurbs_curve_evaluator -> set_order (4);
-          nurbs_curve_evaluator -> reset (total_segments);
+        for (int index = 0; index < total_vertices; ++index) {
+          motion_trail_vertex = &vertex_array[index];
+          nurbs_curve_evaluator = motion_trail_vertex->_nurbs_curve_evaluator;
+          nurbs_curve_evaluator->set_order(4);
+          nurbs_curve_evaluator->reset(total_segments);
         }
       }
 
       // add vertices to each NurbsCurveEvaluator
-      int segment_index;
       CMotionTrailFrame motion_trail_frame_start;
       CMotionTrailFrame motion_trail_frame_end;
 
-      segment_index = 0;
-
       FrameList::iterator frame_iterator;
-      frame_iterator = _frame_list.begin ( );
-      while (segment_index < total_segments) {
-        int vertex_segement_index;
-
+      frame_iterator = _frame_list.begin();
+      for (int segment_index = 0; segment_index < total_segments; ++segment_index) {
         motion_trail_frame_start = *frame_iterator;
         frame_iterator++;
         motion_trail_frame_end = *frame_iterator;
 
         if (_calculate_relative_matrix) {
-          start_transform.multiply (motion_trail_frame_start._transform, inverse_matrix);
-          end_transform.multiply (motion_trail_frame_end._transform, inverse_matrix);
+          start_transform.multiply(motion_trail_frame_start._transform, inverse_matrix);
+          end_transform.multiply(motion_trail_frame_end._transform, inverse_matrix);
         }
         else {
           start_transform = motion_trail_frame_start._transform;
@@ -484,26 +475,27 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
         CMotionTrailVertex *motion_trail_vertex_end;
         PT(NurbsCurveEvaluator) nurbs_curve_evaluator;
 
-        motion_trail_vertex_start = &_vertex_array [0];
+        motion_trail_vertex_start = &vertex_array[0];
 
-        v0 = start_transform.xform (motion_trail_vertex_start -> _vertex);
-        v2 = end_transform.xform (motion_trail_vertex_start -> _vertex);
+        v0 = start_transform.xform(motion_trail_vertex_start->_vertex);
+        v2 = end_transform.xform(motion_trail_vertex_start->_vertex);
 
-        nurbs_curve_evaluator = motion_trail_vertex_start -> _nurbs_curve_evaluator;
-        nurbs_curve_evaluator -> set_vertex (segment_index, v0);
+        nurbs_curve_evaluator = motion_trail_vertex_start->_nurbs_curve_evaluator;
+        nurbs_curve_evaluator->set_vertex(segment_index, v0);
 
-        vertex_segement_index = 0;
-        while (vertex_segement_index < total_vertex_segments) {
-          motion_trail_vertex_start = &_vertex_array [vertex_segement_index];
-          motion_trail_vertex_end = &_vertex_array [vertex_segement_index + 1];
+        for (int vertex_segment_index = 0;
+             vertex_segment_index < total_vertex_segments;
+             ++vertex_segment_index) {
+          motion_trail_vertex_start = &vertex_array[vertex_segment_index];
+          motion_trail_vertex_end = &vertex_array[vertex_segment_index + 1];
 
-          v1 = start_transform.xform (motion_trail_vertex_end -> _vertex);
-          v3 = end_transform.xform (motion_trail_vertex_end -> _vertex);
+          v1 = start_transform.xform(motion_trail_vertex_end->_vertex);
+          v3 = end_transform.xform(motion_trail_vertex_end->_vertex);
 
-          nurbs_curve_evaluator = motion_trail_vertex_end -> _nurbs_curve_evaluator;
+          nurbs_curve_evaluator = motion_trail_vertex_end->_nurbs_curve_evaluator;
 
-          nurbs_curve_evaluator -> set_vertex (segment_index, v1);
-          if (vertex_segement_index == (total_vertex_segments - 1)) {
+          nurbs_curve_evaluator->set_vertex(segment_index, v1);
+          if (vertex_segment_index == (total_vertex_segments - 1)) {
             PN_stdfloat distance;
 
             v = v1 - v3;
@@ -511,72 +503,56 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
             distance = vector.length();
             total_distance += distance;
           }
-
-          vertex_segement_index += 1;
         }
-
-        segment_index += 1;
       }
 
       // evaluate NurbsCurveEvaluator for each vertex
       PT(NurbsCurveResult) *nurbs_curve_result_array;
 
-      nurbs_curve_result_array = new PT(NurbsCurveResult) [total_vertices];
-      for (index = 0; index < total_vertices; index++) {
+      nurbs_curve_result_array = new PT(NurbsCurveResult)[total_vertices];
+      for (int index = 0; index < total_vertices; ++index) {
 
         CMotionTrailVertex *motion_trail_vertex;
         PT(NurbsCurveEvaluator) nurbs_curve_evaluator;
         PT(NurbsCurveResult) nurbs_curve_result;
 
-        motion_trail_vertex = &_vertex_array [index];
+        motion_trail_vertex = &vertex_array[index];
 
-        nurbs_curve_evaluator = motion_trail_vertex -> _nurbs_curve_evaluator;
-        nurbs_curve_result = nurbs_curve_evaluator -> evaluate ( );
-        nurbs_curve_result_array [index] = nurbs_curve_result;
+        nurbs_curve_evaluator = motion_trail_vertex->_nurbs_curve_evaluator;
+        nurbs_curve_result = nurbs_curve_evaluator->evaluate();
+        nurbs_curve_result_array[index] = nurbs_curve_result;
 
         if (debug) {
           PN_stdfloat nurbs_start_t;
           PN_stdfloat nurbs_end_t;
 
-          nurbs_start_t = nurbs_curve_result -> get_start_t();
-          nurbs_end_t = nurbs_curve_result -> get_end_t();
+          nurbs_start_t = nurbs_curve_result->get_start_t();
+          nurbs_end_t = nurbs_curve_result->get_end_t();
 
-          printf ("nurbs_start_t %f, nurbs_end_t %f \n", nurbs_start_t, nurbs_end_t);
+          printf("nurbs_start_t %f, nurbs_end_t %f \n", nurbs_start_t, nurbs_end_t);
         }
       }
 
       // create quads from NurbsCurveResult
-      PN_stdfloat total_curve_segments;
-
-      total_curve_segments = (total_distance / _resolution_distance);
+      PN_stdfloat total_curve_segments = total_distance / _resolution_distance;
       if (total_curve_segments < total_segments) {
         total_curve_segments = total_segments;
       }
 
-      {
-        LVector3 v0;
-        LVector3 v1;
-        LVector3 v2;
-        LVector3 v3;
-
-        LVector4 c0;
-        LVector4 c1;
-        LVector4 c2;
-        LVector4 c3;
+      const int total_curve_segments_int = (int)cceil(total_curve_segments);
+      begin_geometry(total_curve_segments_int * total_vertex_segments);
 
-        LVector2 t0;
-        LVector2 t1;
-        LVector2 t2;
-        LVector2 t3;
+      {
+        LVector3 v0, v1, v2, v3;
+        LVector4 c0, c1, c2, c3;
+        LVector2 t0, t1, t2, t3;
 
         LVector4 vertex_start_color;
         LVector4 vertex_end_color;
 
-        PN_stdfloat curve_segment_index;
-
-        curve_segment_index = 0.0;
-        while (curve_segment_index < total_curve_segments) {
-
+        for (int curve_segment_index = 0;
+             curve_segment_index < total_curve_segments_int;
+             ++curve_segment_index) {
           PN_stdfloat st;
           PN_stdfloat et;
           PN_stdfloat start_t;
@@ -584,17 +560,13 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
           PN_stdfloat color_start_t;
           PN_stdfloat color_end_t;
 
-          int vertex_segement_index;
-
           CMotionTrailVertex *motion_trail_vertex_start;
           CMotionTrailVertex *motion_trail_vertex_end;
           PT(NurbsCurveResult) start_nurbs_curve_result;
           PT(NurbsCurveResult) end_nurbs_curve_result;
 
-          vertex_segement_index = 0;
-
           st = curve_segment_index / total_curve_segments;
-          et = (curve_segment_index + 1.0) / total_curve_segments;
+          et = (curve_segment_index + 1) / total_curve_segments;
 
           start_t = st;
           end_t = et;
@@ -604,36 +576,38 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
             end_t *= end_t;
           }
 
-          motion_trail_vertex_start = &_vertex_array [0];
+          motion_trail_vertex_start = &vertex_array[0];
 
-          vertex_start_color = motion_trail_vertex_start -> _end_color + (motion_trail_vertex_start -> _start_color - motion_trail_vertex_start  -> _end_color);
+          vertex_start_color = motion_trail_vertex_start->_end_color + (motion_trail_vertex_start->_start_color - motion_trail_vertex_start ->_end_color);
 
           color_start_t = color_scale * start_t;
           color_end_t = color_scale * end_t;
 
-          c0 = vertex_start_color * one_minus_x (color_start_t);
-          c2 = vertex_start_color * one_minus_x (color_end_t);
+          c0 = vertex_start_color * one_minus_x(color_start_t);
+          c2 = vertex_start_color * one_minus_x(color_end_t);
 
-          t0.set (one_minus_x (st), motion_trail_vertex_start -> _v);
-          t2.set (one_minus_x (et), motion_trail_vertex_start -> _v);
+          t0.set(one_minus_x(st), motion_trail_vertex_start->_v);
+          t2.set(one_minus_x(et), motion_trail_vertex_start->_v);
 
-          while (vertex_segement_index < total_vertex_segments) {
+          for (int vertex_segment_index = 0;
+               vertex_segment_index < total_vertex_segments;
+               ++vertex_segment_index) {
 
             PN_stdfloat start_nurbs_start_t;
             PN_stdfloat start_nurbs_end_t;
             PN_stdfloat end_nurbs_start_t;
             PN_stdfloat end_nurbs_end_t;
 
-            motion_trail_vertex_start = &_vertex_array [vertex_segement_index];
-            motion_trail_vertex_end = &_vertex_array [vertex_segement_index + 1];
+            motion_trail_vertex_start = &vertex_array[vertex_segment_index];
+            motion_trail_vertex_end = &vertex_array[vertex_segment_index + 1];
 
-            start_nurbs_curve_result = nurbs_curve_result_array [vertex_segement_index];
-            end_nurbs_curve_result = nurbs_curve_result_array [vertex_segement_index + 1];
+            start_nurbs_curve_result = nurbs_curve_result_array[vertex_segment_index];
+            end_nurbs_curve_result = nurbs_curve_result_array[vertex_segment_index + 1];
 
-            start_nurbs_start_t = start_nurbs_curve_result -> get_start_t();
-            start_nurbs_end_t = start_nurbs_curve_result -> get_end_t();
-            end_nurbs_start_t = end_nurbs_curve_result -> get_start_t();
-            end_nurbs_end_t = end_nurbs_curve_result -> get_end_t();
+            start_nurbs_start_t = start_nurbs_curve_result->get_start_t();
+            start_nurbs_end_t = start_nurbs_curve_result->get_end_t();
+            end_nurbs_start_t = end_nurbs_curve_result->get_start_t();
+            end_nurbs_end_t = end_nurbs_curve_result->get_end_t();
 
             PN_stdfloat start_delta_t;
             PN_stdfloat end_delta_t;
@@ -641,23 +615,23 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
             start_delta_t = (start_nurbs_end_t - start_nurbs_start_t);
             end_delta_t = (end_nurbs_end_t - end_nurbs_start_t);
 
-            start_nurbs_curve_result -> eval_point (start_nurbs_start_t + (start_delta_t * st), v0);
-            end_nurbs_curve_result -> eval_point (end_nurbs_start_t + (end_delta_t * st), v1);
+            start_nurbs_curve_result->eval_point(start_nurbs_start_t + (start_delta_t * st), v0);
+            end_nurbs_curve_result->eval_point(end_nurbs_start_t + (end_delta_t * st), v1);
 
-            start_nurbs_curve_result -> eval_point (start_nurbs_start_t + (start_delta_t * et), v2);
-            end_nurbs_curve_result -> eval_point (end_nurbs_start_t + (end_delta_t * et), v3);
+            start_nurbs_curve_result->eval_point(start_nurbs_start_t + (start_delta_t * et), v2);
+            end_nurbs_curve_result->eval_point(end_nurbs_start_t + (end_delta_t * et), v3);
 
             // color
-            vertex_end_color = motion_trail_vertex_end -> _end_color + (motion_trail_vertex_end -> _start_color - motion_trail_vertex_end -> _end_color);
+            vertex_end_color = motion_trail_vertex_end->_end_color + (motion_trail_vertex_end->_start_color - motion_trail_vertex_end->_end_color);
 
-            c1 = vertex_end_color * one_minus_x (color_start_t);
-            c3 = vertex_end_color * one_minus_x (color_end_t);
+            c1 = vertex_end_color * one_minus_x(color_start_t);
+            c3 = vertex_end_color * one_minus_x(color_end_t);
 
             // uv
-            t1.set (one_minus_x (st), motion_trail_vertex_end -> _v);
-            t3.set (one_minus_x (et), motion_trail_vertex_end -> _v);
+            t1.set(one_minus_x(st), motion_trail_vertex_end->_v);
+            t3.set(one_minus_x(et), motion_trail_vertex_end->_v);
 
-            this -> add_geometry_quad (v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3);
+            add_geometry_quad(v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3);
 
             // reuse calculations
             c0 = c1;
@@ -665,26 +639,21 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
 
             t0 = t1;
             t2 = t3;
-
-            vertex_segement_index += 1;
           }
-
-          curve_segment_index += 1.0;
         }
       }
 
-      for (index = 0; index < total_vertices; index++) {
-        nurbs_curve_result_array [index] = nullptr;
+      for (int index = 0; index < total_vertices; ++index) {
+        nurbs_curve_result_array[index] = nullptr;
       }
 
       delete[] nurbs_curve_result_array;
     }
     else {
-
       // non-nurbs version
-      int segment_index;
-      int vertex_segment_index;
-      int total_vertex_segments;
+      const int total_vertex_segments = total_vertices - 1;
+
+      begin_geometry(total_segments * total_vertex_segments);
 
       PN_stdfloat st;
       PN_stdfloat et;
@@ -693,20 +662,9 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
       PN_stdfloat color_start_t;
       PN_stdfloat color_end_t;
 
-      LVector4 v0;
-      LVector4 v1;
-      LVector4 v2;
-      LVector4 v3;
-
-      LVector4 c0;
-      LVector4 c1;
-      LVector4 c2;
-      LVector4 c3;
-
-      LVector2 t0;
-      LVector2 t1;
-      LVector2 t2;
-      LVector2 t3;
+      LVector4 v0, v1, v2, v3;
+      LVector4 c0, c1, c2, c3;
+      LVector2 t0, t1, t2, t3;
 
       LVector4 vertex_start_color;
       LVector4 vertex_end_color;
@@ -714,11 +672,8 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
       CMotionTrailFrame motion_trail_frame_start;
       CMotionTrailFrame motion_trail_frame_end;
 
-      segment_index = 0;
-      FrameList::iterator frame_iterator;
-      frame_iterator = _frame_list.begin ( );
-      while (segment_index < total_segments) {
-
+      FrameList::iterator frame_iterator = _frame_list.begin();
+      for (int segment_index = 0; segment_index < total_segments; ++segment_index) {
         CMotionTrailVertex *motion_trail_vertex_start;
         CMotionTrailVertex *motion_trail_vertex_end;
 
@@ -737,51 +692,49 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
           end_t *= end_t;
         }
 
-        vertex_segment_index = 0;
-        total_vertex_segments = total_vertices - 1;
-
         if (_calculate_relative_matrix) {
-          start_transform.multiply (motion_trail_frame_start._transform, inverse_matrix);
-          end_transform.multiply (motion_trail_frame_end._transform, inverse_matrix);
+          start_transform.multiply(motion_trail_frame_start._transform, inverse_matrix);
+          end_transform.multiply(motion_trail_frame_end._transform, inverse_matrix);
         }
         else {
           start_transform = motion_trail_frame_start._transform;
           end_transform = motion_trail_frame_end._transform;
         }
 
-        motion_trail_vertex_start = &_vertex_array [0];
+        motion_trail_vertex_start = &vertex_array[0];
 
-        v0 = start_transform.xform (motion_trail_vertex_start -> _vertex);
-        v2 = end_transform.xform (motion_trail_vertex_start -> _vertex);
+        v0 = start_transform.xform(motion_trail_vertex_start->_vertex);
+        v2 = end_transform.xform(motion_trail_vertex_start->_vertex);
 
-        vertex_start_color = motion_trail_vertex_start -> _end_color + (motion_trail_vertex_start -> _start_color - motion_trail_vertex_start -> _end_color);
+        vertex_start_color = motion_trail_vertex_start->_end_color + (motion_trail_vertex_start->_start_color - motion_trail_vertex_start->_end_color);
         color_start_t = color_scale * start_t;
         color_end_t = color_scale * end_t;
         c0 = vertex_start_color * color_start_t;
         c2 = vertex_start_color * color_end_t;
 
-        t0.set (st, motion_trail_vertex_start -> _v);
-        t2.set (et, motion_trail_vertex_start -> _v);
-
-        while (vertex_segment_index < total_vertex_segments) {
+        t0.set(st, motion_trail_vertex_start->_v);
+        t2.set(et, motion_trail_vertex_start->_v);
 
-          motion_trail_vertex_start = &_vertex_array [vertex_segment_index];
-          motion_trail_vertex_end = &_vertex_array [vertex_segment_index + 1];
+        for (int vertex_segment_index = 0;
+             vertex_segment_index < total_vertex_segments;
+             ++vertex_segment_index) {
+          motion_trail_vertex_start = &vertex_array[vertex_segment_index];
+          motion_trail_vertex_end = &vertex_array[vertex_segment_index + 1];
 
-          v1 = start_transform.xform (motion_trail_vertex_end -> _vertex);
-          v3 = end_transform.xform (motion_trail_vertex_end -> _vertex);
+          v1 = start_transform.xform(motion_trail_vertex_end->_vertex);
+          v3 = end_transform.xform(motion_trail_vertex_end->_vertex);
 
           // color
-          vertex_end_color = motion_trail_vertex_end -> _end_color + (motion_trail_vertex_end -> _start_color - motion_trail_vertex_end -> _end_color);
+          vertex_end_color = motion_trail_vertex_end->_end_color + (motion_trail_vertex_end->_start_color - motion_trail_vertex_end->_end_color);
 
           c1 = vertex_end_color * color_start_t;
           c3 = vertex_end_color * color_end_t;
 
           // uv
-          t1.set (st, motion_trail_vertex_end -> _v);
-          t3.set (et, motion_trail_vertex_end -> _v);
+          t1.set(st, motion_trail_vertex_end->_v);
+          t3.set(et, motion_trail_vertex_end->_v);
 
-          this -> add_geometry_quad (v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3);
+          add_geometry_quad(v0, v1, v2, v3, c0, c1, c2, c3, t0, t1, t2, t3);
 
           // reuse calculations
           v0 = v1;
@@ -792,18 +745,12 @@ update_motion_trail (PN_stdfloat current_time, LMatrix4 *transform) {
 
           t0 = t1;
           t2 = t3;
-
-          vertex_segment_index += 1;
         }
-
-        segment_index += 1;
       }
     }
 
-    // end geometry
-    this -> end_geometry ( );
+    end_geometry();
 
-    delete[] _vertex_array;
-    _vertex_array = nullptr;
+    delete[] vertex_array;
   }
 }

+ 1 - 0
direct/src/motiontrail/cMotionTrail.h

@@ -91,6 +91,7 @@ PUBLISHED:
 public:
 
   void begin_geometry();
+  void begin_geometry(int num_quads);
   void add_geometry_quad(LVector3 &v0, LVector3 &v1, LVector3 &v2, LVector3 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
   void add_geometry_quad(LVector4 &v0, LVector4 &v1, LVector4 &v2, LVector4 &v3, LVector4 &c0, LVector4 &c1, LVector4 &c2, LVector4 &c3, LVector2 &t0, LVector2 &t1, LVector2 &t2, LVector2 &t3);
   void end_geometry();

+ 92 - 0
doc/ReleaseNotes

@@ -1,3 +1,95 @@
+-----------------------  RELEASE 1.10.13  -----------------------
+
+This is a significant release containing many important bug fixes and a couple
+of interesting new features.
+
+Rendering
+* Fix single texture stage limit when `gl-version 3 2` or higher is set (#1404)
+* Fix some render-to-texture bugs with multithreaded pipeline (incl. #1364)
+* Fix failure to unset divisor after rendering with hardware instancing
+* Add "MSAA" filter to CommonFilters class as convenience to enable MSAA
+* Fix multisample FBOs with MRT resolving aux target into color target
+* Fix shader generator not responding to fog color changes
+* Fix OpenGL error when downloading GL_LUMINANCE8 texture
+
+Windowing
+* Fix incorrect "without" event generation when mouse leaves window (#1400)
+* Windows: Fix lost "up" events when dragging cursor outside window while
+  multiple mouse buttons are pressed down (#1396)
+* macOS: Fix crash with threading-model on newer macOS versions (#1286)
+* macOS: Fix black screen when going fullscreen on Apple M1-based macs (#1316)
+* macOS: Fix window overlapping Dock when requesting very large height
+* macOS: Improve application termination handling, now sends proper exit events
+* X11: tinydisplay handles window resizes more efficiently
+* X11: Work around window not rendering at first on swaywm (#1087)
+
+Deployment
+* Not all code was being built with optimize level 2
+* Add `keep_docstrings` option to switch to optimize level 1 (#1341)
+* Add `prefer_discrete_gpu` option to force dedicated GPU on Windows (#680)
+* Add `bam_model_extensions` for converting non-egg models to .bam (#714)
+* Work around autodiscovery error when using `setuptools>=61.0.0` (#1394)
+* Default Linux target to `manylinux2014_x86_64` on Python 3.11+
+
+PStats
+* Add support for Python profiling with `pstats-python-profiler` Config.prc var
+* Fix PStats crash at launch from pip installs in newer Linux distros (#1391)
+* Performance improvements to time-based strip chart views
+* Time-based strip charts now can show start/stop count in corner of graphs
+* Optimize client performance when sending a large number of samples
+* Fix dropped frames by changing value for `pstats-max-queue-size` from 1 to 4
+* Server accept clients using PStats protocol version 2.3
+
+Assimp
+* Fix assertion when loading meshes with multiple primitive types
+* Add `assimp-collapse-dummy-root-node` option to remove root node (see #366)
+* Import custom object properties as tags
+* Add support for additional texture maps, including PBR textures
+* Support reading tangent and binormal vectors
+* Improve performance when loading geometry
+* Fix problems reading external files (see #366)
+* Support reading alpha mode when loading .glTF models
+* Add support for texture transforms
+* Add support for texture wrapping modes
+* Fix memory corruption bugs
+
+Build
+* Fixes to `pview.desktop` file on Linux
+* makepanda: Fix problems when building on arm64 on macOS without `--arch` flag
+* makepanda: Fix detection issues with newer macOS / XCode versions
+* makepanda: Fix motiontrail header files not being copied
+* Windows: Fix HTTPClient not working when nativenet module is disabled
+* macOS: Fix OpenCV library refusing to load in arm64 build (#1393)
+* Fix compiler error when compiling for e2k (MCST Elbrus 2000) (#1367)
+
+Miscellaneous
+* Add new motion trails sample program
+* `MotionTrail.add_vertex()` method now directly accepts a vertex position
+* Significant performance optimization of C++-based motion trail implementation
+* Fix race condition when destructing/constructing NodePaths in thread (#1366)
+* Add implementation of capsule-into-polygon collision test (#1369)
+* Fix texture transforms sometimes not being flattened (#1392)
+* Fix support for `#pragma include <file.glsl>` in GLSL shaders
+* Fix `ShaderBuffer.prepare()` not doing anything
+* Fix bf-cbc encryption no longer working when building with OpenSSL 3.0
+* PandaNode bounds_type property was erroneously marked read-only
+* Fix warnings when copying OdeTriMeshGeom objects
+* Fix a crash when using `Notify.set_ostream_ptr()` from Python (#1371)
+* Fix GarbageReport not working with Python 3 (#1304)
+* Make `mat.cols[n]` and `mat.rows[n]` assignable
+* Fix `ExecutionEnvironment.args` being empty on Linux
+* Add various useful functions to interrogatedb module
+* Fix Python 3 issues unpacking uint types in Python 3 (#1380)
+* Fix interrogate syntax error with C++11-style attributes in declarators
+* Fix regression with BufferViewer in double-precision build (#1365)
+* Fix `PandaNode.nested_vertices` not updating properly
+* Add `do_events()` and `process_event()` snake_case aliases in eventMgr
+* Support second arg of None in `replace_texture()` / `replace_material()`
+* Support `os.fspath()` for ConfigVariableFilename objects (#1406)
+* rplight: Fix PSSM calculation failing with infinite far distance (#1397)
+* Remove spurious print in `direct.showutil.Effects.createBounce()` (#1383)
+* Fix assorted compiler warnings
+
 -----------------------  RELEASE 1.10.12  -----------------------
 
 Recommended maintenance release containing primarily bug fixes.

+ 10 - 1
panda/src/cocoadisplay/cocoaGraphicsWindow.mm

@@ -924,10 +924,19 @@ set_properties_now(WindowProperties &properties) {
     NSRect frame;
     NSRect container;
     if (_window != nil) {
-      frame = [_window contentRectForFrameRect:[_window frame]];
+      NSRect window_frame = [_window frame];
+      frame = [_window contentRectForFrameRect:window_frame];
       NSScreen *screen = [_window screen];
       nassertv(screen != nil);
       container = [screen frame];
+
+      // Prevent the centering from overlapping the Dock
+      if (y < 0) {
+        NSRect visible_frame = [screen visibleFrame];
+        if (window_frame.size.height == visible_frame.size.height) {
+          y = 0;
+        }
+      }
     } else {
       frame = [_view frame];
       container = [[_view superview] frame];

+ 81 - 0
samples/motion-trails/fireball.py

@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+
+from random import choice
+
+from panda3d.core import Point3, Vec4
+from direct.showbase.ShowBase import ShowBase
+from direct.motiontrail.MotionTrail import MotionTrail
+from direct.interval.LerpInterval import LerpPosInterval, LerpHprInterval
+from direct.interval.LerpInterval import LerpScaleInterval
+from direct.interval.LerpInterval import LerpTexOffsetInterval
+from direct.interval.IntervalGlobal import Sequence
+
+
+base = ShowBase()
+base.set_background_color(0.1, 0.1, 0.1, 1)
+
+base.cam.set_pos(0, -128, 32)
+base.cam.look_at(render)
+
+flame_colors = (
+    Vec4(1.0, 0.0, 0.0, 1),
+    Vec4(1.0, 0.2, 0.0, 1),
+    Vec4(1.0, 0.7, 0.0, 1),
+    Vec4(0.0, 0.0, 0.2, 1),
+)
+
+# A NodePath, rotating in empty space.
+pivot = render.attach_new_node("pivot")
+pivot.hprInterval(3, (360, 0, 0)).loop()
+Sequence( # Bobs up and down
+    LerpPosInterval(pivot, 0.3, (0, 0,-2), (0, 0, 1), blendType="easeInOut"),
+    LerpPosInterval(pivot, 0.5, (0, 0, 1), (0, 0,-2), blendType="easeInOut")
+).loop()
+
+# A little chunk of charcoal that rotates along the pivot with an offset.
+charcoal = loader.load_model("models/smiley").copy_to(pivot)
+charcoal.set_texture(loader.load_texture("models/plasma.png"), 1)
+charcoal.set_color(flame_colors[0] * 1.5)
+charcoal.set_x(-32)
+
+# It leaves a trail of flames.
+fire_trail = MotionTrail("fire trail", charcoal)
+fire_trail.register_motion_trail()
+fire_trail.geom_node_path.reparent_to(render)
+fire_trail.set_texture(loader.load_texture("models/plasma.png"))
+fire_trail.time_window = 3 # Length of trail
+
+# A circle as the trail's shape, by plotting a NodePath in a circle.
+center = render.attach_new_node("center")
+around = center.attach_new_node("around")
+around.set_z(1)
+res = 8 # Amount of angles in "circle". Higher is smoother.
+for i in range(res + 1):
+    center.set_r((360 / res) * i)
+    vertex_pos = around.get_pos(render)
+    fire_trail.add_vertex(vertex_pos)
+
+    start_color = flame_colors[i % len(flame_colors)] * 1.7
+    end_color = Vec4(1, 1, 0, 1)
+    fire_trail.set_vertex_color(i, start_color, end_color)
+
+'''
+# A simple flat line, tron lightcycle-style, would be like so:
+
+fire_trail.add_vertex(Point3(0, 0, 1))
+fire_trail.add_vertex(Point3(0, 0,-1))
+fire_trail.set_vertex_color(0, flame_colors[0], flame_colors[0])
+fire_trail.set_vertex_color(1, flame_colors[1], flame_colors[1])
+'''
+
+fire_trail.update_vertices()
+
+# Adding intervals to the trail to give it swoops and bends.
+LerpHprInterval(fire_trail, 2, (0, 0, -360)).loop()
+LerpTexOffsetInterval(fire_trail.geom_node_path, 4, (1, 1), (1, 0)).loop()
+Sequence( # Grow and shrink
+    LerpScaleInterval(fire_trail, 0.3, 1.4, 0.4, blendType="easeInOut"),
+    LerpScaleInterval(fire_trail, 0.5, 0.4, 1.4, blendType="easeInOut")
+).loop()
+
+base.run()

+ 0 - 0
samples/motion-trails/main.py → samples/motion-trails/framebuffer-feedback.py


BIN
samples/motion-trails/models/plasma.png