|
|
@@ -41,6 +41,7 @@ PStatCollector GeomVertexData::_animation_pcollector("*:Animation");
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
GeomVertexData::
|
|
|
GeomVertexData() :
|
|
|
+ _usage_hint(UH_unspecified),
|
|
|
_char_pcollector(_animation_pcollector, "unnamed"),
|
|
|
_skinning_pcollector(_char_pcollector, "Skinning"),
|
|
|
_morphs_pcollector(_char_pcollector, "Morphs")
|
|
|
@@ -58,6 +59,7 @@ GeomVertexData(const string &name,
|
|
|
GeomVertexData::UsageHint usage_hint) :
|
|
|
_name(name),
|
|
|
_format(format),
|
|
|
+ _usage_hint(UH_unspecified),
|
|
|
_char_pcollector(PStatCollector(_animation_pcollector, name)),
|
|
|
_skinning_pcollector(_char_pcollector, "Skinning"),
|
|
|
_morphs_pcollector(_char_pcollector, "Morphs")
|
|
|
@@ -67,13 +69,11 @@ GeomVertexData(const string &name,
|
|
|
set_usage_hint(usage_hint);
|
|
|
|
|
|
// Create some empty arrays as required by the format.
|
|
|
- CDWriter cdata(_cycler);
|
|
|
-
|
|
|
int num_arrays = _format->get_num_arrays();
|
|
|
for (int i = 0; i < num_arrays; i++) {
|
|
|
PT(GeomVertexArrayData) array = new GeomVertexArrayData
|
|
|
(_format->get_array(i), usage_hint);
|
|
|
- cdata->_arrays.push_back(array);
|
|
|
+ _arrays.push_back(array);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -87,15 +87,21 @@ GeomVertexData(const GeomVertexData ©) :
|
|
|
TypedWritableReferenceCount(copy),
|
|
|
_name(copy._name),
|
|
|
_format(copy._format),
|
|
|
- _cycler(copy._cycler),
|
|
|
+ _usage_hint(copy._usage_hint),
|
|
|
+ _arrays(copy._arrays),
|
|
|
+ _transform_table(copy._transform_table),
|
|
|
+ _transform_blend_table(copy._transform_blend_table),
|
|
|
+ _slider_table(copy._slider_table),
|
|
|
+ _animated_vertices(copy._animated_vertices),
|
|
|
+ _animated_vertices_modified(copy._animated_vertices_modified),
|
|
|
+ _modified(copy._modified),
|
|
|
_char_pcollector(copy._char_pcollector),
|
|
|
_skinning_pcollector(copy._skinning_pcollector),
|
|
|
_morphs_pcollector(copy._morphs_pcollector)
|
|
|
{
|
|
|
- CDWriter cdata(_cycler);
|
|
|
// It's important that we *not* copy the animated_vertices pointer.
|
|
|
- cdata->_animated_vertices = NULL;
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _animated_vertices = NULL;
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -112,7 +118,7 @@ GeomVertexData(const GeomVertexData ©,
|
|
|
TypedWritableReferenceCount(copy),
|
|
|
_name(copy._name),
|
|
|
_format(format),
|
|
|
- _cycler(copy._cycler),
|
|
|
+ _usage_hint(UH_unspecified),
|
|
|
_char_pcollector(copy._char_pcollector),
|
|
|
_skinning_pcollector(copy._skinning_pcollector),
|
|
|
_morphs_pcollector(copy._morphs_pcollector)
|
|
|
@@ -120,20 +126,18 @@ GeomVertexData(const GeomVertexData ©,
|
|
|
nassertv(_format->is_registered());
|
|
|
|
|
|
// Create some empty arrays as required by the format.
|
|
|
- CDWriter cdata(_cycler);
|
|
|
-
|
|
|
- UsageHint usage_hint = cdata->_usage_hint;
|
|
|
- cdata->_arrays.clear();
|
|
|
+ UsageHint usage_hint = _usage_hint;
|
|
|
+ _arrays.clear();
|
|
|
int num_arrays = _format->get_num_arrays();
|
|
|
for (int i = 0; i < num_arrays; i++) {
|
|
|
PT(GeomVertexArrayData) array = new GeomVertexArrayData
|
|
|
(_format->get_array(i), usage_hint);
|
|
|
- cdata->_arrays.push_back(array);
|
|
|
+ _arrays.push_back(array);
|
|
|
}
|
|
|
|
|
|
// It's important that we *not* copy the animated_vertices pointer.
|
|
|
- cdata->_animated_vertices = NULL;
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _animated_vertices = NULL;
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -146,15 +150,22 @@ operator = (const GeomVertexData ©) {
|
|
|
TypedWritableReferenceCount::operator = (copy);
|
|
|
_name = copy._name;
|
|
|
_format = copy._format;
|
|
|
- _cycler = copy._cycler;
|
|
|
_char_pcollector = copy._char_pcollector;
|
|
|
_skinning_pcollector = copy._skinning_pcollector;
|
|
|
_morphs_pcollector = copy._morphs_pcollector;
|
|
|
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _usage_hint = copy._usage_hint;
|
|
|
+ _arrays = copy._arrays;
|
|
|
+ _transform_table = copy._transform_table;
|
|
|
+ _transform_blend_table = copy._transform_blend_table;
|
|
|
+ _slider_table = copy._slider_table;
|
|
|
+ _animated_vertices = copy._animated_vertices;
|
|
|
+ _animated_vertices_modified = copy._animated_vertices_modified;
|
|
|
+
|
|
|
+ clear_cache();
|
|
|
+
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -164,23 +175,13 @@ operator = (const GeomVertexData ©) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
GeomVertexData::
|
|
|
~GeomVertexData() {
|
|
|
- // When we destruct, we should ensure that all of our cached
|
|
|
- // entries, across all pipeline stages, are properly removed from
|
|
|
- // the cache manager.
|
|
|
- int num_stages = _cycler.get_num_stages();
|
|
|
- for (int i = 0; i < num_stages; i++) {
|
|
|
- if (_cycler.is_stage_unique(i)) {
|
|
|
- CData *cdata = _cycler.write_stage(i);
|
|
|
- for (Cache::iterator ci = cdata->_cache.begin();
|
|
|
- ci != cdata->_cache.end();
|
|
|
- ++ci) {
|
|
|
- CacheEntry *entry = (*ci);
|
|
|
- entry->erase();
|
|
|
- }
|
|
|
- cdata->_cache.clear();
|
|
|
- _cycler.release_write_stage(i, cdata);
|
|
|
- }
|
|
|
+ for (Cache::iterator ci = _cache.begin();
|
|
|
+ ci != _cache.end();
|
|
|
+ ++ci) {
|
|
|
+ CacheEntry *entry = (*ci);
|
|
|
+ entry->erase();
|
|
|
}
|
|
|
+ _cache.clear();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -206,21 +207,20 @@ set_name(const string &name) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::
|
|
|
set_usage_hint(GeomVertexData::UsageHint usage_hint) {
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- cdata->_usage_hint = usage_hint;
|
|
|
+ _usage_hint = usage_hint;
|
|
|
|
|
|
Arrays::iterator ai;
|
|
|
- for (ai = cdata->_arrays.begin();
|
|
|
- ai != cdata->_arrays.end();
|
|
|
+ for (ai = _arrays.begin();
|
|
|
+ ai != _arrays.end();
|
|
|
++ai) {
|
|
|
if ((*ai)->get_ref_count() > 1) {
|
|
|
(*ai) = new GeomVertexArrayData(*(*ai));
|
|
|
}
|
|
|
(*ai)->set_usage_hint(usage_hint);
|
|
|
}
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -232,8 +232,7 @@ set_usage_hint(GeomVertexData::UsageHint usage_hint) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
int GeomVertexData::
|
|
|
get_num_rows() const {
|
|
|
- CDReader cdata(_cycler);
|
|
|
- nassertr(_format->get_num_arrays() == (int)cdata->_arrays.size(), 0);
|
|
|
+ nassertr(_format->get_num_arrays() == (int)_arrays.size(), 0);
|
|
|
if (_format->get_num_arrays() == 0) {
|
|
|
// No arrays means no rows. Weird but legal.
|
|
|
return 0;
|
|
|
@@ -241,7 +240,98 @@ get_num_rows() const {
|
|
|
|
|
|
// Look up the answer on the first array (since any array will do).
|
|
|
int stride = _format->get_array(0)->get_stride();
|
|
|
- return cdata->_arrays[0]->get_data_size_bytes() / stride;
|
|
|
+ return _arrays[0]->get_data_size_bytes() / stride;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: GeomVertexData::set_num_rows
|
|
|
+// Access: Published
|
|
|
+// Description: Sets the length of the array to n rows in all of
|
|
|
+// the various arrays (presumably by adding rows).
|
|
|
+//
|
|
|
+// The new vertex data is initialized to 0, except for
|
|
|
+// the "color" column, which is initialized to (1, 1, 1,
|
|
|
+// 1).
|
|
|
+//
|
|
|
+// The return value is true if the number of rows
|
|
|
+// was changed, false if the object already contained n
|
|
|
+// rows (or if there was some error).
|
|
|
+//
|
|
|
+// Although this method is Published, application code
|
|
|
+// only very rarely has any need to call it. Instead,
|
|
|
+// you should use the GeomVertexWriter to build up the
|
|
|
+// rows in a GeomVertexData object automatically,
|
|
|
+// without need to explicitly set the number of
|
|
|
+// rows.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool GeomVertexData::
|
|
|
+set_num_rows(int n) {
|
|
|
+ nassertr(_format->get_num_arrays() == (int)_arrays.size(), false);
|
|
|
+
|
|
|
+ bool any_changed = false;
|
|
|
+
|
|
|
+ int color_array = -1;
|
|
|
+ int orig_color_rows = -1;
|
|
|
+
|
|
|
+ for (size_t i = 0; i < _arrays.size(); i++) {
|
|
|
+ if (_arrays[i]->get_num_rows() != n) {
|
|
|
+ // Copy-on-write.
|
|
|
+ if (_arrays[i]->get_ref_count() > 1) {
|
|
|
+ _arrays[i] = new GeomVertexArrayData(*_arrays[i]);
|
|
|
+ }
|
|
|
+ if (_arrays[i]->has_column(InternalName::get_color())) {
|
|
|
+ color_array = i;
|
|
|
+ orig_color_rows = _arrays[i]->get_num_rows();
|
|
|
+ }
|
|
|
+ _arrays[i]->set_num_rows(n);
|
|
|
+ any_changed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (color_array >= 0 && orig_color_rows < n) {
|
|
|
+ // We have just added some rows, fill the "color" column with
|
|
|
+ // (1, 1, 1, 1), for the programmer's convenience.
|
|
|
+ GeomVertexArrayData *array_data = _arrays[color_array];
|
|
|
+ const GeomVertexColumn *column =
|
|
|
+ array_data->get_array_format()->get_column(InternalName::get_color());
|
|
|
+ int stride = array_data->get_array_format()->get_stride();
|
|
|
+ unsigned char *start =
|
|
|
+ array_data->modify_data() + column->get_start();
|
|
|
+ unsigned char *stop = start + array_data->get_data_size_bytes();
|
|
|
+ unsigned char *pointer = start + stride * orig_color_rows;
|
|
|
+ int num_values = column->get_num_values();
|
|
|
+
|
|
|
+ switch (column->get_numeric_type()) {
|
|
|
+ case NT_packed_dcba:
|
|
|
+ case NT_packed_dabc:
|
|
|
+ case NT_uint8:
|
|
|
+ case NT_uint16:
|
|
|
+ case NT_uint32:
|
|
|
+ while (pointer < stop) {
|
|
|
+ memset(pointer, 0xff, column->get_total_bytes());
|
|
|
+ pointer += stride;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case NT_float32:
|
|
|
+ while (pointer < stop) {
|
|
|
+ PN_float32 *pi = (PN_float32 *)pointer;
|
|
|
+ for (int i = 0; i < num_values; i++) {
|
|
|
+ pi[i] = 1.0f;
|
|
|
+ }
|
|
|
+ pointer += stride;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (any_changed) {
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices.clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ return any_changed;
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -253,21 +343,20 @@ get_num_rows() const {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::
|
|
|
clear_rows() {
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- nassertv(_format->get_num_arrays() == (int)cdata->_arrays.size());
|
|
|
+ nassertv(_format->get_num_arrays() == (int)_arrays.size());
|
|
|
|
|
|
Arrays::iterator ai;
|
|
|
- for (ai = cdata->_arrays.begin();
|
|
|
- ai != cdata->_arrays.end();
|
|
|
+ for (ai = _arrays.begin();
|
|
|
+ ai != _arrays.end();
|
|
|
++ai) {
|
|
|
if ((*ai)->get_ref_count() > 1) {
|
|
|
(*ai) = new GeomVertexArrayData(*(*ai));
|
|
|
}
|
|
|
(*ai)->clear_rows();
|
|
|
}
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices.clear();
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices.clear();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -285,17 +374,16 @@ modify_array(int i) {
|
|
|
// Perform copy-on-write: if the reference count on the vertex data
|
|
|
// is greater than 1, assume some other GeomVertexData has the same
|
|
|
// pointer, so make a copy of it first.
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- nassertr(i >= 0 && i < (int)cdata->_arrays.size(), NULL);
|
|
|
+ nassertr(i >= 0 && i < (int)_arrays.size(), NULL);
|
|
|
|
|
|
- if (cdata->_arrays[i]->get_ref_count() > 1) {
|
|
|
- cdata->_arrays[i] = new GeomVertexArrayData(*cdata->_arrays[i]);
|
|
|
+ if (_arrays[i]->get_ref_count() > 1) {
|
|
|
+ _arrays[i] = new GeomVertexArrayData(*_arrays[i]);
|
|
|
}
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
|
|
|
- return cdata->_arrays[i];
|
|
|
+ return _arrays[i];
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -308,12 +396,11 @@ modify_array(int i) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::
|
|
|
set_array(int i, const GeomVertexArrayData *array) {
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- nassertv(i >= 0 && i < (int)cdata->_arrays.size());
|
|
|
- cdata->_arrays[i] = (GeomVertexArrayData *)array;
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ nassertv(i >= 0 && i < (int)_arrays.size());
|
|
|
+ _arrays[i] = (GeomVertexArrayData *)array;
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -329,11 +416,10 @@ void GeomVertexData::
|
|
|
set_transform_table(const TransformTable *table) {
|
|
|
nassertv(table == (TransformTable *)NULL || table->is_registered());
|
|
|
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- cdata->_transform_table = (TransformTable *)table;
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _transform_table = (TransformTable *)table;
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -349,16 +435,14 @@ modify_transform_blend_table() {
|
|
|
// Perform copy-on-write: if the reference count on the table is
|
|
|
// greater than 1, assume some other GeomVertexData has the same
|
|
|
// pointer, so make a copy of it first.
|
|
|
- CDWriter cdata(_cycler);
|
|
|
-
|
|
|
- if (cdata->_transform_blend_table->get_ref_count() > 1) {
|
|
|
- cdata->_transform_blend_table = new TransformBlendTable(*cdata->_transform_blend_table);
|
|
|
+ if (_transform_blend_table->get_ref_count() > 1) {
|
|
|
+ _transform_blend_table = new TransformBlendTable(*_transform_blend_table);
|
|
|
}
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
|
|
|
- return cdata->_transform_blend_table;
|
|
|
+ return _transform_blend_table;
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -372,11 +456,10 @@ modify_transform_blend_table() {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::
|
|
|
set_transform_blend_table(const TransformBlendTable *table) {
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- cdata->_transform_blend_table = (TransformBlendTable *)table;
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _transform_blend_table = (TransformBlendTable *)table;
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -394,11 +477,10 @@ void GeomVertexData::
|
|
|
set_slider_table(const SliderTable *table) {
|
|
|
nassertv(table == (SliderTable *)NULL || table->is_registered());
|
|
|
|
|
|
- CDWriter cdata(_cycler);
|
|
|
- cdata->_slider_table = (SliderTable *)table;
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices_modified = UpdateSeq();
|
|
|
+ _slider_table = (SliderTable *)table;
|
|
|
+ clear_cache();
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+ _animated_vertices_modified = UpdateSeq();
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -409,12 +491,10 @@ set_slider_table(const SliderTable *table) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
int GeomVertexData::
|
|
|
get_num_bytes() const {
|
|
|
- CDReader cdata(_cycler);
|
|
|
-
|
|
|
int num_bytes = sizeof(GeomVertexData);
|
|
|
|
|
|
Arrays::const_iterator ai;
|
|
|
- for (ai = cdata->_arrays.begin(); ai != cdata->_arrays.end(); ++ai) {
|
|
|
+ for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
|
|
|
num_bytes += (*ai)->get_data_size_bytes();
|
|
|
}
|
|
|
|
|
|
@@ -674,11 +754,10 @@ convert_to(const GeomVertexFormat *new_format) const {
|
|
|
// Look up the new format in our cache--maybe we've recently applied
|
|
|
// it.
|
|
|
{
|
|
|
- CDReader cdata(_cycler);
|
|
|
CacheEntry temp_entry(new_format);
|
|
|
temp_entry.local_object();
|
|
|
- Cache::const_iterator ci = cdata->_cache.find(&temp_entry);
|
|
|
- if (ci != cdata->_cache.end()) {
|
|
|
+ Cache::const_iterator ci = _cache.find(&temp_entry);
|
|
|
+ if (ci != _cache.end()) {
|
|
|
CacheEntry *entry = (*ci);
|
|
|
// Record a cache hit, so this element will stay in the cache a
|
|
|
// while longer.
|
|
|
@@ -706,9 +785,8 @@ convert_to(const GeomVertexFormat *new_format) const {
|
|
|
// Record the new result in the cache.
|
|
|
CacheEntry *entry;
|
|
|
{
|
|
|
- CDWriter cdata(((GeomVertexData *)this)->_cycler);
|
|
|
entry = new CacheEntry((GeomVertexData *)this, new_format, new_data);
|
|
|
- bool inserted = cdata->_cache.insert(entry).second;
|
|
|
+ bool inserted = ((GeomVertexData *)this)->_cache.insert(entry).second;
|
|
|
nassertr(inserted, new_data);
|
|
|
}
|
|
|
|
|
|
@@ -878,24 +956,22 @@ set_color(const Colorf &color, int num_components,
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
CPT(GeomVertexData) GeomVertexData::
|
|
|
animate_vertices() const {
|
|
|
- CDReader cdata(_cycler);
|
|
|
-
|
|
|
if (_format->get_animation().get_animation_type() != AT_panda) {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
UpdateSeq modified;
|
|
|
- if (cdata->_transform_blend_table != (TransformBlendTable *)NULL) {
|
|
|
- if (cdata->_slider_table != (SliderTable *)NULL) {
|
|
|
+ if (_transform_blend_table != (TransformBlendTable *)NULL) {
|
|
|
+ if (_slider_table != (SliderTable *)NULL) {
|
|
|
modified =
|
|
|
- max(cdata->_transform_blend_table->get_modified(),
|
|
|
- cdata->_slider_table->get_modified());
|
|
|
+ max(_transform_blend_table->get_modified(),
|
|
|
+ _slider_table->get_modified());
|
|
|
} else {
|
|
|
- modified = cdata->_transform_blend_table->get_modified();
|
|
|
+ modified = _transform_blend_table->get_modified();
|
|
|
}
|
|
|
|
|
|
- } else if (cdata->_slider_table != (SliderTable *)NULL) {
|
|
|
- modified = cdata->_slider_table->get_modified();
|
|
|
+ } else if (_slider_table != (SliderTable *)NULL) {
|
|
|
+ modified = _slider_table->get_modified();
|
|
|
|
|
|
} else {
|
|
|
// No transform blend table or slider table--ergo, no vertex
|
|
|
@@ -903,15 +979,14 @@ animate_vertices() const {
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
- if (cdata->_animated_vertices_modified == modified &&
|
|
|
- cdata->_animated_vertices != (GeomVertexData *)NULL) {
|
|
|
+ if (_animated_vertices_modified == modified &&
|
|
|
+ _animated_vertices != (GeomVertexData *)NULL) {
|
|
|
// No changes.
|
|
|
- return cdata->_animated_vertices;
|
|
|
+ return _animated_vertices;
|
|
|
}
|
|
|
- CDWriter cdataw(((GeomVertexData *)this)->_cycler, cdata);
|
|
|
- cdataw->_animated_vertices_modified = modified;
|
|
|
- ((GeomVertexData *)this)->update_animated_vertices(cdataw);
|
|
|
- return cdataw->_animated_vertices;
|
|
|
+ ((GeomVertexData *)this)->_animated_vertices_modified = modified;
|
|
|
+ ((GeomVertexData *)this)->update_animated_vertices();
|
|
|
+ return _animated_vertices;
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -1069,6 +1144,23 @@ write(ostream &out, int indent_level) const {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: GeomVertexData::clear_cache
|
|
|
+// Access: Published
|
|
|
+// Description: Removes all of the previously-cached results of
|
|
|
+// convert_to().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+void GeomVertexData::
|
|
|
+clear_cache() {
|
|
|
+ for (Cache::iterator ci = _cache.begin();
|
|
|
+ ci != _cache.end();
|
|
|
+ ++ci) {
|
|
|
+ CacheEntry *entry = (*ci);
|
|
|
+ entry->erase();
|
|
|
+ }
|
|
|
+ _cache.clear();
|
|
|
+}
|
|
|
+
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: GeomVertexData::get_array_info
|
|
|
// Access: Public
|
|
|
@@ -1092,8 +1184,7 @@ get_array_info(const InternalName *name,
|
|
|
int array_index;
|
|
|
const GeomVertexColumn *column;
|
|
|
if (_format->get_array_info(name, array_index, column)) {
|
|
|
- CDReader cdata(_cycler);
|
|
|
- array_data = cdata->_arrays[array_index];
|
|
|
+ array_data = _arrays[array_index];
|
|
|
num_values = column->get_num_values();
|
|
|
numeric_type = column->get_numeric_type();
|
|
|
start = column->get_start();
|
|
|
@@ -1118,8 +1209,7 @@ get_vertex_info(const GeomVertexArrayData *&array_data,
|
|
|
if (array_index >= 0) {
|
|
|
const GeomVertexColumn *column = _format->get_vertex_column();
|
|
|
|
|
|
- CDReader cdata(_cycler);
|
|
|
- array_data = cdata->_arrays[array_index];
|
|
|
+ array_data = _arrays[array_index];
|
|
|
num_values = column->get_num_values();
|
|
|
numeric_type = column->get_numeric_type();
|
|
|
start = column->get_start();
|
|
|
@@ -1145,8 +1235,7 @@ get_normal_info(const GeomVertexArrayData *&array_data,
|
|
|
const GeomVertexColumn *column = _format->get_normal_column();
|
|
|
nassertr(column->get_num_values() == 3, false);
|
|
|
|
|
|
- CDReader cdata(_cycler);
|
|
|
- array_data = cdata->_arrays[array_index];
|
|
|
+ array_data = _arrays[array_index];
|
|
|
numeric_type = column->get_numeric_type();
|
|
|
start = column->get_start();
|
|
|
stride = _format->get_array(array_index)->get_stride();
|
|
|
@@ -1170,8 +1259,7 @@ get_color_info(const GeomVertexArrayData *&array_data,
|
|
|
if (array_index >= 0) {
|
|
|
const GeomVertexColumn *column = _format->get_color_column();
|
|
|
|
|
|
- CDReader cdata(_cycler);
|
|
|
- array_data = cdata->_arrays[array_index];
|
|
|
+ array_data = _arrays[array_index];
|
|
|
num_values = column->get_num_values();
|
|
|
numeric_type = column->get_numeric_type();
|
|
|
start = column->get_start();
|
|
|
@@ -1237,81 +1325,6 @@ uint8_rgba_to_packed_argb(unsigned char *to, int to_stride,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::do_set_num_rows
|
|
|
-// Access: Private
|
|
|
-// Description: The private implementation of set_num_rows().
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-bool GeomVertexData::
|
|
|
-do_set_num_rows(int n, GeomVertexData::CData *cdata) {
|
|
|
- nassertr(_format->get_num_arrays() == (int)cdata->_arrays.size(), false);
|
|
|
-
|
|
|
- bool any_changed = false;
|
|
|
-
|
|
|
- int color_array = -1;
|
|
|
- int orig_color_rows = -1;
|
|
|
-
|
|
|
- for (size_t i = 0; i < cdata->_arrays.size(); i++) {
|
|
|
- if (cdata->_arrays[i]->get_num_rows() != n) {
|
|
|
- // Copy-on-write.
|
|
|
- if (cdata->_arrays[i]->get_ref_count() > 1) {
|
|
|
- cdata->_arrays[i] = new GeomVertexArrayData(*cdata->_arrays[i]);
|
|
|
- }
|
|
|
- if (cdata->_arrays[i]->has_column(InternalName::get_color())) {
|
|
|
- color_array = i;
|
|
|
- orig_color_rows = cdata->_arrays[i]->get_num_rows();
|
|
|
- }
|
|
|
- cdata->_arrays[i]->set_num_rows(n);
|
|
|
- any_changed = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (color_array >= 0 && orig_color_rows < n) {
|
|
|
- // We have just added some rows, fill the "color" column with
|
|
|
- // (1, 1, 1, 1), for the programmer's convenience.
|
|
|
- GeomVertexArrayData *array_data = cdata->_arrays[color_array];
|
|
|
- const GeomVertexColumn *column =
|
|
|
- array_data->get_array_format()->get_column(InternalName::get_color());
|
|
|
- int stride = array_data->get_array_format()->get_stride();
|
|
|
- unsigned char *start =
|
|
|
- array_data->modify_data() + column->get_start();
|
|
|
- unsigned char *stop = start + array_data->get_data_size_bytes();
|
|
|
- unsigned char *pointer = start + stride * orig_color_rows;
|
|
|
- int num_values = column->get_num_values();
|
|
|
-
|
|
|
- switch (column->get_numeric_type()) {
|
|
|
- case NT_packed_dcba:
|
|
|
- case NT_packed_dabc:
|
|
|
- case NT_uint8:
|
|
|
- case NT_uint16:
|
|
|
- case NT_uint32:
|
|
|
- while (pointer < stop) {
|
|
|
- memset(pointer, 0xff, column->get_total_bytes());
|
|
|
- pointer += stride;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case NT_float32:
|
|
|
- while (pointer < stop) {
|
|
|
- PN_float32 *pi = (PN_float32 *)pointer;
|
|
|
- for (int i = 0; i < num_values; i++) {
|
|
|
- pi[i] = 1.0f;
|
|
|
- }
|
|
|
- pointer += stride;
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (any_changed) {
|
|
|
- do_clear_cache(cdata);
|
|
|
- cdata->_modified = Geom::get_next_modified();
|
|
|
- cdata->_animated_vertices.clear();
|
|
|
- }
|
|
|
-
|
|
|
- return any_changed;
|
|
|
-}
|
|
|
-
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: GeomVertexData::update_animated_vertices
|
|
|
// Access: Private
|
|
|
@@ -1320,7 +1333,7 @@ do_set_num_rows(int n, GeomVertexData::CData *cdata) {
|
|
|
// existing animated_vertices object.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::
|
|
|
-update_animated_vertices(GeomVertexData::CData *cdata) {
|
|
|
+update_animated_vertices() {
|
|
|
int num_rows = get_num_rows();
|
|
|
|
|
|
if (gobj_cat.is_debug()) {
|
|
|
@@ -1331,13 +1344,13 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
|
|
|
|
|
|
PStatTimer timer(_char_pcollector);
|
|
|
|
|
|
- if (cdata->_animated_vertices == (GeomVertexData *)NULL) {
|
|
|
+ if (_animated_vertices == (GeomVertexData *)NULL) {
|
|
|
CPT(GeomVertexFormat) new_format = _format->get_post_animated_format();
|
|
|
- cdata->_animated_vertices =
|
|
|
+ _animated_vertices =
|
|
|
new GeomVertexData(get_name(), new_format,
|
|
|
min(get_usage_hint(), UH_dynamic));
|
|
|
}
|
|
|
- PT(GeomVertexData) new_data = cdata->_animated_vertices;
|
|
|
+ PT(GeomVertexData) new_data = _animated_vertices;
|
|
|
|
|
|
// We have to make a complete copy of the data first so we can
|
|
|
// modify it. If we were clever, we could maybe just figure out the
|
|
|
@@ -1347,7 +1360,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
|
|
|
new_data->copy_from(this, true);
|
|
|
|
|
|
// First, apply all of the morphs.
|
|
|
- CPT(SliderTable) slider_table = cdata->_slider_table;
|
|
|
+ CPT(SliderTable) slider_table = _slider_table;
|
|
|
if (slider_table != (SliderTable *)NULL) {
|
|
|
PStatTimer timer2(_morphs_pcollector);
|
|
|
int num_morphs = _format->get_num_morphs();
|
|
|
@@ -1398,7 +1411,7 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
|
|
|
}
|
|
|
|
|
|
// Then apply the transforms.
|
|
|
- CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table;
|
|
|
+ CPT(TransformBlendTable) tb_table = _transform_blend_table;
|
|
|
if (tb_table != (TransformBlendTable *)NULL) {
|
|
|
PStatTimer timer3(_skinning_pcollector);
|
|
|
|
|
|
@@ -1454,24 +1467,6 @@ update_animated_vertices(GeomVertexData::CData *cdata) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::do_clear_cache
|
|
|
-// Access: Private
|
|
|
-// Description: The private implementation of clear_cache().
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void GeomVertexData::
|
|
|
-do_clear_cache(GeomVertexData::CData *cdata) {
|
|
|
- // Probably we shouldn't do anything at all here unless we are
|
|
|
- // running in pipeline stage 0.
|
|
|
- for (Cache::iterator ci = cdata->_cache.begin();
|
|
|
- ci != cdata->_cache.end();
|
|
|
- ++ci) {
|
|
|
- CacheEntry *entry = (*ci);
|
|
|
- entry->erase();
|
|
|
- }
|
|
|
- cdata->_cache.clear();
|
|
|
-}
|
|
|
-
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
// Function: GeomVertexData::register_with_read_factory
|
|
|
// Access: Public, Static
|
|
|
@@ -1496,7 +1491,17 @@ write_datagram(BamWriter *manager, Datagram &dg) {
|
|
|
dg.add_string(_name);
|
|
|
manager->write_pointer(dg, _format);
|
|
|
|
|
|
- manager->write_cdata(dg, _cycler);
|
|
|
+ dg.add_uint8(_usage_hint);
|
|
|
+
|
|
|
+ dg.add_uint16(_arrays.size());
|
|
|
+ Arrays::const_iterator ai;
|
|
|
+ for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
|
|
|
+ manager->write_pointer(dg, *ai);
|
|
|
+ }
|
|
|
+
|
|
|
+ manager->write_pointer(dg, _transform_table);
|
|
|
+ manager->write_pointer(dg, _transform_blend_table);
|
|
|
+ manager->write_pointer(dg, _slider_table);
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -1533,6 +1538,17 @@ complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|
|
|
|
|
_format = DCAST(GeomVertexFormat, p_list[pi++]);
|
|
|
|
|
|
+ Arrays::iterator ai;
|
|
|
+ for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
|
|
|
+ (*ai) = DCAST(GeomVertexArrayData, p_list[pi++]);
|
|
|
+ }
|
|
|
+
|
|
|
+ _transform_table = DCAST(TransformTable, p_list[pi++]);
|
|
|
+ _transform_blend_table = DCAST(TransformBlendTable, p_list[pi++]);
|
|
|
+ _slider_table = DCAST(SliderTable, p_list[pi++]);
|
|
|
+
|
|
|
+ _modified = Geom::get_next_modified();
|
|
|
+
|
|
|
return pi;
|
|
|
}
|
|
|
|
|
|
@@ -1559,34 +1575,32 @@ finalize(BamReader *manager) {
|
|
|
// This extends to the nested array datas, as well as the transform
|
|
|
// table and slider tables, as well.
|
|
|
|
|
|
- CDWriter cdata(_cycler);
|
|
|
-
|
|
|
CPT(GeomVertexFormat) new_format =
|
|
|
GeomVertexFormat::register_format(_format);
|
|
|
|
|
|
- for (size_t i = 0; i < cdata->_arrays.size(); ++i) {
|
|
|
+ for (size_t i = 0; i < _arrays.size(); ++i) {
|
|
|
CPT(GeomVertexArrayFormat) new_array_format = new_format->get_array(i);
|
|
|
- nassertv(cdata->_arrays[i]->_array_format->compare_to(*new_array_format) == 0);
|
|
|
+ nassertv(_arrays[i]->_array_format->compare_to(*new_array_format) == 0);
|
|
|
|
|
|
- manager->change_pointer(cdata->_arrays[i]->_array_format, new_array_format);
|
|
|
- cdata->_arrays[i]->_array_format = new_array_format;
|
|
|
+ manager->change_pointer(_arrays[i]->_array_format, new_array_format);
|
|
|
+ _arrays[i]->_array_format = new_array_format;
|
|
|
}
|
|
|
|
|
|
manager->change_pointer(_format, new_format);
|
|
|
_format = new_format;
|
|
|
|
|
|
- if (cdata->_transform_table != (TransformTable *)NULL) {
|
|
|
+ if (_transform_table != (TransformTable *)NULL) {
|
|
|
CPT(TransformTable) new_transform_table =
|
|
|
- TransformTable::register_table(cdata->_transform_table);
|
|
|
- manager->change_pointer(cdata->_transform_table, new_transform_table);
|
|
|
- cdata->_transform_table = new_transform_table;
|
|
|
+ TransformTable::register_table(_transform_table);
|
|
|
+ manager->change_pointer(_transform_table, new_transform_table);
|
|
|
+ _transform_table = new_transform_table;
|
|
|
}
|
|
|
|
|
|
- if (cdata->_slider_table != (SliderTable *)NULL) {
|
|
|
+ if (_slider_table != (SliderTable *)NULL) {
|
|
|
CPT(SliderTable) new_slider_table =
|
|
|
- SliderTable::register_table(cdata->_slider_table);
|
|
|
- manager->change_pointer(cdata->_slider_table, new_slider_table);
|
|
|
- cdata->_slider_table = new_slider_table;
|
|
|
+ SliderTable::register_table(_slider_table);
|
|
|
+ manager->change_pointer(_slider_table, new_slider_table);
|
|
|
+ _slider_table = new_slider_table;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -1604,7 +1618,18 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|
|
set_name(scan.get_string());
|
|
|
manager->read_pointer(scan);
|
|
|
|
|
|
- manager->read_cdata(scan, _cycler);
|
|
|
+ _usage_hint = (UsageHint)scan.get_uint8();
|
|
|
+
|
|
|
+ size_t num_arrays = scan.get_uint16();
|
|
|
+ _arrays.reserve(num_arrays);
|
|
|
+ for (size_t i = 0; i < num_arrays; ++i) {
|
|
|
+ manager->read_pointer(scan);
|
|
|
+ _arrays.push_back(NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ manager->read_pointer(scan);
|
|
|
+ manager->read_pointer(scan);
|
|
|
+ manager->read_pointer(scan);
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -1615,16 +1640,10 @@ fillin(DatagramIterator &scan, BamReader *manager) {
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
void GeomVertexData::CacheEntry::
|
|
|
evict_callback() {
|
|
|
- // We have to operate on stage 0 of the pipeline, since that's where
|
|
|
- // the cache really counts. Because of the multistage pipeline, we
|
|
|
- // might not actually have a cache entry there (it might have been
|
|
|
- // added to stage 1 instead). No big deal if we don't.
|
|
|
- CData *cdata = _source->_cycler.write_stage(0);
|
|
|
- Cache::iterator ci = cdata->_cache.find(this);
|
|
|
- if (ci != cdata->_cache.end()) {
|
|
|
- cdata->_cache.erase(ci);
|
|
|
+ Cache::iterator ci = _source->_cache.find(this);
|
|
|
+ if (ci != _source->_cache.end()) {
|
|
|
+ _source->_cache.erase(ci);
|
|
|
}
|
|
|
- _source->_cycler.release_write_stage(0, cdata);
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
@@ -1637,82 +1656,3 @@ output(ostream &out) const {
|
|
|
out << "vertex data " << (void *)_source << " to "
|
|
|
<< *_modifier;
|
|
|
}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::CData::make_copy
|
|
|
-// Access: Public, Virtual
|
|
|
-// Description:
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-CycleData *GeomVertexData::CData::
|
|
|
-make_copy() const {
|
|
|
- return new CData(*this);
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::CData::write_datagram
|
|
|
-// Access: Public, Virtual
|
|
|
-// Description: Writes the contents of this object to the datagram
|
|
|
-// for shipping out to a Bam file.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void GeomVertexData::CData::
|
|
|
-write_datagram(BamWriter *manager, Datagram &dg) const {
|
|
|
- dg.add_uint8(_usage_hint);
|
|
|
-
|
|
|
- dg.add_uint16(_arrays.size());
|
|
|
- Arrays::const_iterator ai;
|
|
|
- for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
|
|
|
- manager->write_pointer(dg, *ai);
|
|
|
- }
|
|
|
-
|
|
|
- manager->write_pointer(dg, _transform_table);
|
|
|
- manager->write_pointer(dg, _transform_blend_table);
|
|
|
- manager->write_pointer(dg, _slider_table);
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::CData::complete_pointers
|
|
|
-// Access: Public, Virtual
|
|
|
-// Description: Receives an array of pointers, one for each time
|
|
|
-// manager->read_pointer() was called in fillin().
|
|
|
-// Returns the number of pointers processed.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-int GeomVertexData::CData::
|
|
|
-complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
|
|
- int pi = CycleData::complete_pointers(p_list, manager);
|
|
|
-
|
|
|
- Arrays::iterator ai;
|
|
|
- for (ai = _arrays.begin(); ai != _arrays.end(); ++ai) {
|
|
|
- (*ai) = DCAST(GeomVertexArrayData, p_list[pi++]);
|
|
|
- }
|
|
|
-
|
|
|
- _transform_table = DCAST(TransformTable, p_list[pi++]);
|
|
|
- _transform_blend_table = DCAST(TransformBlendTable, p_list[pi++]);
|
|
|
- _slider_table = DCAST(SliderTable, p_list[pi++]);
|
|
|
-
|
|
|
- _modified = Geom::get_next_modified();
|
|
|
-
|
|
|
- return pi;
|
|
|
-}
|
|
|
-
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-// Function: GeomVertexData::CData::fillin
|
|
|
-// Access: Public, Virtual
|
|
|
-// Description: This internal function is called by make_from_bam to
|
|
|
-// read in all of the relevant data from the BamFile for
|
|
|
-// the new GeomVertexData.
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
-void GeomVertexData::CData::
|
|
|
-fillin(DatagramIterator &scan, BamReader *manager) {
|
|
|
- _usage_hint = (UsageHint)scan.get_uint8();
|
|
|
-
|
|
|
- size_t num_arrays = scan.get_uint16();
|
|
|
- _arrays.reserve(num_arrays);
|
|
|
- for (size_t i = 0; i < num_arrays; ++i) {
|
|
|
- manager->read_pointer(scan);
|
|
|
- _arrays.push_back(NULL);
|
|
|
- }
|
|
|
-
|
|
|
- manager->read_pointer(scan);
|
|
|
- manager->read_pointer(scan);
|
|
|
- manager->read_pointer(scan);
|
|
|
-}
|