mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-01 01:07:51 -04:00
GeomVertexData::reserve_num_rows() and related changes--big performance improvement, especially on Windows
This commit is contained in:
parent
d114ab235e
commit
372532346e
@ -411,7 +411,14 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
|
||||
// Add each new primitive to the Geom.
|
||||
Primitives::const_iterator pi;
|
||||
for (pi = primitives.begin(); pi != primitives.end(); ++pi) {
|
||||
GeomPrimitive *primitive = (*pi);
|
||||
PT(GeomPrimitive) primitive = (*pi);
|
||||
|
||||
if (primitive->is_indexed()) {
|
||||
// Since we may have over-allocated while we were filling up
|
||||
// the primitives, down-allocate now.
|
||||
primitive->reserve_num_vertices(primitive->get_num_vertices());
|
||||
}
|
||||
|
||||
geom->add_primitive(primitive);
|
||||
}
|
||||
|
||||
@ -2313,6 +2320,7 @@ make_vertex_data(const EggRenderState *render_state,
|
||||
// dynamic.
|
||||
PT(GeomVertexData) vertex_data =
|
||||
new GeomVertexData(name, format, Geom::UH_static);
|
||||
vertex_data->reserve_num_rows(vertex_pool->size());
|
||||
|
||||
vertex_data->set_transform_blend_table(blend_table);
|
||||
if (slider_table != (SliderTable *)NULL) {
|
||||
@ -2543,6 +2551,12 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
|
||||
if (result.second) {
|
||||
// This was the first primitive of this type. Store it.
|
||||
primitives.push_back(primitive);
|
||||
|
||||
if (egg2pg_cat.is_debug()) {
|
||||
egg2pg_cat.debug()
|
||||
<< "First primitive of type " << primitive->get_type()
|
||||
<< ": " << primitive << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
GeomPrimitive *orig_prim = (*result.first).second;
|
||||
@ -2556,6 +2570,12 @@ make_primitive(const EggRenderState *render_state, EggPrimitive *egg_prim,
|
||||
// If the old primitive is full, keep the new primitive from now
|
||||
// on.
|
||||
(*result.first).second = primitive;
|
||||
|
||||
if (egg2pg_cat.is_debug()) {
|
||||
egg2pg_cat.debug()
|
||||
<< "Next primitive of type " << primitive->get_type()
|
||||
<< ": " << primitive << "\n";
|
||||
}
|
||||
primitives.push_back(primitive);
|
||||
}
|
||||
|
||||
|
@ -188,6 +188,11 @@ void GeomPrimitive::
|
||||
add_vertex(int vertex) {
|
||||
CDWriter cdata(_cycler, true);
|
||||
|
||||
if (gobj_cat.is_spam()) {
|
||||
gobj_cat.spam()
|
||||
<< this << ".add_vertex(" << vertex << ")\n";
|
||||
}
|
||||
|
||||
consider_elevate_index_type(cdata, vertex);
|
||||
|
||||
int num_primitives = get_num_primitives();
|
||||
@ -320,6 +325,42 @@ add_next_vertices(int num_vertices) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::reserve_num_vertices
|
||||
// Access: Published
|
||||
// Description: This ensures that enough memory space for n vertices
|
||||
// is allocated, so that you may increase the number of
|
||||
// vertices to n without causing a new memory
|
||||
// allocation. This is a performance optimization only;
|
||||
// it is especially useful when you know ahead of time
|
||||
// that you will be adding n vertices to the primitive.
|
||||
//
|
||||
// Note that the total you specify here should also
|
||||
// include implicit vertices which may be added at each
|
||||
// close_primitive() call, according to
|
||||
// get_num_unused_vertices_per_primitive().
|
||||
//
|
||||
// Note also that making this call will implicitly make
|
||||
// the primitive indexed if it is not already, which
|
||||
// could result in a performance *penalty*. If you
|
||||
// would prefer not to lose the nonindexed nature of
|
||||
// your existing GeomPrimitives, check is_indexed()
|
||||
// before making this call.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomPrimitive::
|
||||
reserve_num_vertices(int num_vertices) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< this << ".reserve_num_vertices(" << num_vertices << ")\n";
|
||||
}
|
||||
|
||||
CDWriter cdata(_cycler, true);
|
||||
consider_elevate_index_type(cdata, num_vertices);
|
||||
do_make_indexed(cdata);
|
||||
PT(GeomVertexArrayData) array_obj = cdata->_vertices.get_write_pointer();
|
||||
array_obj->reserve_num_rows(num_vertices);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomPrimitive::close_primitive
|
||||
// Access: Published
|
||||
@ -1646,7 +1687,9 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
||||
cdata->_maxs = make_index_data();
|
||||
|
||||
GeomVertexWriter mins(cdata->_mins.get_write_pointer(), 0);
|
||||
mins.reserve_num_rows(cdata->_ends.size());
|
||||
GeomVertexWriter maxs(cdata->_maxs.get_write_pointer(), 0);
|
||||
maxs.reserve_num_rows(cdata->_ends.size());
|
||||
|
||||
int pi = 0;
|
||||
|
||||
@ -1711,9 +1754,15 @@ recompute_minmax(GeomPrimitive::CData *cdata) {
|
||||
void GeomPrimitive::
|
||||
do_make_indexed(CData *cdata) {
|
||||
if (cdata->_vertices.is_null()) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< this << ".make_indexed()\n";
|
||||
}
|
||||
|
||||
nassertv(cdata->_num_vertices != -1);
|
||||
cdata->_vertices = make_index_data();
|
||||
GeomVertexWriter index(cdata->_vertices.get_write_pointer(), 0);
|
||||
index.reserve_num_rows(cdata->_num_vertices);
|
||||
for (int i = 0; i < cdata->_num_vertices; ++i) {
|
||||
index.add_data1i(i + cdata->_first_vertex);
|
||||
}
|
||||
@ -1762,6 +1811,11 @@ void GeomPrimitive::
|
||||
do_set_index_type(CData *cdata, GeomPrimitive::NumericType index_type) {
|
||||
cdata->_index_type = index_type;
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< this << ".set_index_type(" << index_type << ")\n";
|
||||
}
|
||||
|
||||
if (!cdata->_vertices.is_null()) {
|
||||
CPT(GeomVertexArrayFormat) new_format = get_index_format();
|
||||
|
||||
|
@ -105,6 +105,7 @@ PUBLISHED:
|
||||
INLINE void add_vertices(int v1, int v2, int v3, int v4);
|
||||
void add_consecutive_vertices(int start, int num_vertices);
|
||||
void add_next_vertices(int num_vertices);
|
||||
void reserve_num_vertices(int num_vertices);
|
||||
bool close_primitive();
|
||||
void clear_vertices();
|
||||
void offset_vertices(int offset);
|
||||
|
@ -106,6 +106,21 @@ unclean_set_num_rows(int n) {
|
||||
return modify_handle()->unclean_set_num_rows(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexArrayData::reserve_num_rows
|
||||
// Access: Published
|
||||
// Description: This ensures that enough memory space for n rows is
|
||||
// allocated, so that you may increase the number of
|
||||
// rows to n without causing a new memory allocation.
|
||||
// This is a performance optimization only; it is
|
||||
// especially useful when you know ahead of time that
|
||||
// you will be adding n rows to the data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool GeomVertexArrayData::
|
||||
reserve_num_rows(int n) {
|
||||
return modify_handle()->reserve_num_rows(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexArrayData::clear_rows
|
||||
// Access: Published
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "configVariableInt.h"
|
||||
#include "simpleAllocator.h"
|
||||
#include "vertexDataBuffer.h"
|
||||
#include "texture.h"
|
||||
|
||||
ConfigVariableInt max_independent_vertex_data
|
||||
("max-independent-vertex-data", -1,
|
||||
@ -641,12 +642,14 @@ fillin(DatagramIterator &scan, BamReader *manager, void *extra_data) {
|
||||
PTA_uchar new_data;
|
||||
READ_PTA(manager, scan, array_data->read_raw_data, new_data);
|
||||
_buffer.unclean_realloc(new_data.size());
|
||||
_buffer.set_size(new_data.size());
|
||||
memcpy(_buffer.get_write_pointer(), &new_data[0], new_data.size());
|
||||
|
||||
} else {
|
||||
// Now, the array data is just stored directly.
|
||||
size_t size = scan.get_uint32();
|
||||
_buffer.unclean_realloc(size);
|
||||
_buffer.set_size(size);
|
||||
|
||||
const unsigned char *source_data =
|
||||
(const unsigned char *)scan.get_datagram().get_data();
|
||||
@ -712,8 +715,29 @@ set_num_rows(int n) {
|
||||
size_t new_size = n * stride;
|
||||
size_t orig_size = _cdata->_buffer.get_size();
|
||||
|
||||
if (gobj_cat.is_spam()) {
|
||||
gobj_cat.spam()
|
||||
<< _object << ".set_num_rows(" << n << "), size = " << new_size << "\n";
|
||||
}
|
||||
|
||||
if (new_size != orig_size) {
|
||||
_cdata->_buffer.clean_realloc(new_size);
|
||||
size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
|
||||
if (new_size > orig_reserved_size) {
|
||||
// Add more rows. Go up to the next power of two bytes, mainly
|
||||
// to reduce the number of allocs needed.
|
||||
size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)new_size);
|
||||
nassertr(new_reserved_size >= new_size, false);
|
||||
|
||||
_cdata->_buffer.clean_realloc(new_reserved_size);
|
||||
|
||||
} else if (new_size == 0) {
|
||||
// If we set the number of rows to 0, go ahead and clear the
|
||||
// buffer altogether, and let the user build it up again from
|
||||
// nothing, to try to reduce frivolous memory waste.
|
||||
_cdata->_buffer.clear();
|
||||
}
|
||||
|
||||
_cdata->_buffer.set_size(new_size);
|
||||
|
||||
// Now ensure that the newly-added rows are initialized to 0.
|
||||
if (new_size > orig_size) {
|
||||
@ -726,9 +750,12 @@ set_num_rows(int n) {
|
||||
if (get_current_thread()->get_pipeline_stage() == 0) {
|
||||
_object->set_lru_size(_cdata->_buffer.get_size());
|
||||
}
|
||||
|
||||
nassertr(get_num_rows() == n, true);
|
||||
return true;
|
||||
}
|
||||
|
||||
nassertr(get_num_rows() == n, false);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -745,16 +772,26 @@ unclean_set_num_rows(int n) {
|
||||
int stride = _object->_array_format->get_stride();
|
||||
size_t new_size = n * stride;
|
||||
size_t orig_size = _cdata->_buffer.get_size();
|
||||
size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
|
||||
|
||||
if (new_size != orig_size || new_size != orig_reserved_size) {
|
||||
// Since this is unclean_set_num_rows(), we won't be using it to
|
||||
// incrementally increase the array; instead, it will generally be
|
||||
// used only to create an array initially. So it makes sense to
|
||||
// set the reserved size to precisely the same as the target size.
|
||||
|
||||
if (new_size != orig_size) {
|
||||
_cdata->_buffer.unclean_realloc(new_size);
|
||||
_cdata->_buffer.set_size(new_size);
|
||||
|
||||
// No need to fill to zero or copy the old buffer, since this is
|
||||
// unclean_set_num_rows().
|
||||
|
||||
_cdata->_modified = Geom::get_next_modified();
|
||||
if (new_size != orig_size) {
|
||||
_cdata->_modified = Geom::get_next_modified();
|
||||
|
||||
if (get_current_thread()->get_pipeline_stage() == 0) {
|
||||
_object->set_lru_size(_cdata->_buffer.get_size());
|
||||
if (get_current_thread()->get_pipeline_stage() == 0) {
|
||||
_object->set_lru_size(_cdata->_buffer.get_size());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -762,6 +799,38 @@ unclean_set_num_rows(int n) {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexArrayDataHandle::reserve_num_rows
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GeomVertexArrayDataHandle::
|
||||
reserve_num_rows(int n) {
|
||||
nassertr(_writable, false);
|
||||
mark_used();
|
||||
|
||||
int stride = _object->_array_format->get_stride();
|
||||
size_t new_reserved_size = n * stride;
|
||||
new_reserved_size = max(_cdata->_buffer.get_size(), new_reserved_size);
|
||||
size_t orig_reserved_size = _cdata->_buffer.get_reserved_size();
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< _object << ".reserve_num_rows(" << n << "), size = " << new_reserved_size << "\n";
|
||||
}
|
||||
|
||||
if (new_reserved_size != orig_reserved_size) {
|
||||
// We allow the user to set the alloc point smaller with this
|
||||
// call, assuming the user knows what he's doing. This allows the
|
||||
// user to reduce wasted memory after completely filling up a
|
||||
// buffer.
|
||||
_cdata->_buffer.clean_realloc(new_reserved_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexArrayDataHandle::copy_data_from
|
||||
// Access: Public
|
||||
@ -773,11 +842,12 @@ copy_data_from(const GeomVertexArrayDataHandle *other) {
|
||||
mark_used();
|
||||
other->mark_used();
|
||||
|
||||
_cdata->_buffer.unclean_realloc(other->_cdata->_buffer.get_size());
|
||||
size_t size = other->_cdata->_buffer.get_size();
|
||||
_cdata->_buffer.unclean_realloc(size);
|
||||
_cdata->_buffer.set_size(size);
|
||||
|
||||
unsigned char *dest = _cdata->_buffer.get_write_pointer();
|
||||
const unsigned char *source = other->_cdata->_buffer.get_read_pointer(true);
|
||||
size_t size = other->_cdata->_buffer.get_size();
|
||||
memcpy(dest, source, size);
|
||||
|
||||
_cdata->_modified = Geom::get_next_modified();
|
||||
@ -819,11 +889,18 @@ copy_subdata_from(size_t to_start, size_t to_size,
|
||||
memmove(pointer + to_start + to_size,
|
||||
pointer + to_start + from_size,
|
||||
to_buffer_orig_size - (to_start + to_size));
|
||||
to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
|
||||
to_buffer.set_size(to_buffer_orig_size + from_size - to_size);
|
||||
|
||||
} else if (to_size < from_size) {
|
||||
// Expand the array.
|
||||
to_buffer.clean_realloc(to_buffer_orig_size + from_size - to_size);
|
||||
size_t needed_size = to_buffer_orig_size + from_size - to_size;
|
||||
size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size();
|
||||
if (needed_size > to_buffer_orig_reserved_size) {
|
||||
size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size);
|
||||
to_buffer.clean_realloc(new_reserved_size);
|
||||
}
|
||||
to_buffer.set_size(needed_size);
|
||||
|
||||
unsigned char *pointer = to_buffer.get_write_pointer();
|
||||
memmove(pointer + to_start + to_size,
|
||||
pointer + to_start + from_size,
|
||||
@ -854,6 +931,7 @@ set_data(const string &data) {
|
||||
mark_used();
|
||||
|
||||
_cdata->_buffer.unclean_realloc(data.size());
|
||||
_cdata->_buffer.set_size(data.size());
|
||||
memcpy(_cdata->_buffer.get_write_pointer(), data.data(), data.size());
|
||||
|
||||
_cdata->_modified = Geom::get_next_modified();
|
||||
@ -891,11 +969,18 @@ set_subdata(size_t start, size_t size, const string &data) {
|
||||
memmove(pointer + start + from_size,
|
||||
pointer + start + size,
|
||||
to_buffer_orig_size - (start + size));
|
||||
to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
|
||||
to_buffer.set_size(to_buffer_orig_size + from_size - size);
|
||||
|
||||
} else if (size < from_size) {
|
||||
// Expand the array.
|
||||
to_buffer.clean_realloc(to_buffer_orig_size + from_size - size);
|
||||
size_t needed_size = to_buffer_orig_size + from_size - size;
|
||||
size_t to_buffer_orig_reserved_size = to_buffer.get_reserved_size();
|
||||
if (needed_size > to_buffer_orig_reserved_size) {
|
||||
size_t new_reserved_size = (size_t)Texture::up_to_power_2((int)needed_size);
|
||||
to_buffer.clean_realloc(new_reserved_size);
|
||||
}
|
||||
to_buffer.set_size(needed_size);
|
||||
|
||||
unsigned char *pointer = to_buffer.get_write_pointer();
|
||||
memmove(pointer + start + from_size,
|
||||
pointer + start + size,
|
||||
|
@ -87,6 +87,7 @@ PUBLISHED:
|
||||
INLINE int get_num_rows() const;
|
||||
INLINE bool set_num_rows(int n);
|
||||
INLINE bool unclean_set_num_rows(int n);
|
||||
INLINE bool reserve_num_rows(int n);
|
||||
INLINE void clear_rows();
|
||||
|
||||
INLINE int get_data_size_bytes() const;
|
||||
@ -274,6 +275,7 @@ PUBLISHED:
|
||||
INLINE int get_num_rows() const;
|
||||
bool set_num_rows(int n);
|
||||
bool unclean_set_num_rows(int n);
|
||||
bool reserve_num_rows(int n);
|
||||
INLINE void clear_rows();
|
||||
|
||||
INLINE int get_data_size_bytes() const;
|
||||
|
@ -143,6 +143,23 @@ unclean_set_num_rows(int n) {
|
||||
return writer.unclean_set_num_rows(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::reserve_num_rows
|
||||
// Access: Published
|
||||
// Description: This ensures that enough memory space for n rows is
|
||||
// allocated, so that you may increase the number of
|
||||
// rows to n without causing a new memory allocation.
|
||||
// This is a performance optimization only; it is
|
||||
// especially useful when you know ahead of time that
|
||||
// you will be adding n rows to the data.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool GeomVertexData::
|
||||
reserve_num_rows(int n) {
|
||||
GeomVertexDataPipelineWriter writer(this, true, Thread::get_current_thread());
|
||||
writer.check_array_writers();
|
||||
return writer.reserve_num_rows(n);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::get_num_arrays
|
||||
// Access: Published
|
||||
|
@ -542,6 +542,7 @@ copy_from(const GeomVertexData *source, bool keep_data_objects,
|
||||
}
|
||||
|
||||
// Now make sure the arrays we didn't share are all filled in.
|
||||
reserve_num_rows(num_rows);
|
||||
set_num_rows(num_rows);
|
||||
|
||||
// Now go back through and copy any data that's left over.
|
||||
@ -2273,8 +2274,9 @@ unclean_set_num_rows(int n) {
|
||||
|
||||
for (size_t i = 0; i < _cdata->_arrays.size(); i++) {
|
||||
if (_array_writers[i]->get_num_rows() != n) {
|
||||
_array_writers[i]->unclean_set_num_rows(n);
|
||||
any_changed = true;
|
||||
if (_array_writers[i]->unclean_set_num_rows(n)) {
|
||||
any_changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2287,6 +2289,27 @@ unclean_set_num_rows(int n) {
|
||||
return any_changed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexDataPipelineWriter::reserve_num_rows
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GeomVertexDataPipelineWriter::
|
||||
reserve_num_rows(int n) {
|
||||
nassertr(_got_array_writers, false);
|
||||
nassertr(_cdata->_format->get_num_arrays() == (int)_cdata->_arrays.size(), false);
|
||||
|
||||
bool any_changed = false;
|
||||
|
||||
for (size_t i = 0; i < _cdata->_arrays.size(); i++) {
|
||||
if (_array_writers[i]->reserve_num_rows(n)) {
|
||||
any_changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return any_changed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexDataPipelineWriter::modify_array
|
||||
// Access: Public
|
||||
|
@ -105,6 +105,7 @@ PUBLISHED:
|
||||
INLINE int get_num_rows() const;
|
||||
INLINE bool set_num_rows(int n);
|
||||
INLINE bool unclean_set_num_rows(int n);
|
||||
INLINE bool reserve_num_rows(int n);
|
||||
void clear_rows();
|
||||
|
||||
INLINE int get_num_arrays() const;
|
||||
@ -487,6 +488,7 @@ public:
|
||||
int get_num_rows() const;
|
||||
bool set_num_rows(int n);
|
||||
bool unclean_set_num_rows(int n);
|
||||
bool reserve_num_rows(int n);
|
||||
|
||||
private:
|
||||
void make_array_writers();
|
||||
|
@ -65,6 +65,37 @@ set_column(int array, const GeomVertexColumn *column) {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexWriter::reserve_num_rows
|
||||
// Access: Published
|
||||
// Description: This ensures that enough memory space for num_rows is
|
||||
// allocated, so that you may add up to num_rows rows
|
||||
// without causing a new memory allocation. This is a
|
||||
// performance optimization only; it is especially
|
||||
// useful when you know the number of rows you will be
|
||||
// adding ahead of time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool GeomVertexWriter::
|
||||
reserve_num_rows(int num_rows) {
|
||||
bool result;
|
||||
|
||||
if (_vertex_data != (GeomVertexData *)NULL) {
|
||||
// If we have a whole GeomVertexData, we must set the length of
|
||||
// all its arrays at once.
|
||||
GeomVertexDataPipelineWriter writer(_vertex_data, true, _current_thread);
|
||||
writer.check_array_writers();
|
||||
result = writer.reserve_num_rows(num_rows);
|
||||
_handle = writer.get_array_writer(_array);
|
||||
|
||||
} else {
|
||||
// Otherwise, we can get away with modifying only the one array
|
||||
// we're using.
|
||||
result = _handle->reserve_num_rows(num_rows);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexWriter::output
|
||||
// Access: Published
|
||||
|
@ -101,6 +101,7 @@ PUBLISHED:
|
||||
INLINE bool set_column(const InternalName *name);
|
||||
bool set_column(int array, const GeomVertexColumn *column);
|
||||
INLINE void clear();
|
||||
bool reserve_num_rows(int num_rows);
|
||||
|
||||
INLINE bool has_column() const;
|
||||
INLINE int get_array() const;
|
||||
|
@ -21,7 +21,8 @@
|
||||
INLINE VertexDataBuffer::
|
||||
VertexDataBuffer() :
|
||||
_resident_data(NULL),
|
||||
_size(0)
|
||||
_size(0),
|
||||
_reserved_size(0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -33,9 +34,11 @@ VertexDataBuffer() :
|
||||
INLINE VertexDataBuffer::
|
||||
VertexDataBuffer(size_t size) :
|
||||
_resident_data(NULL),
|
||||
_size(0)
|
||||
_size(0),
|
||||
_reserved_size(0)
|
||||
{
|
||||
do_unclean_realloc(size);
|
||||
_size = size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -46,7 +49,8 @@ VertexDataBuffer(size_t size) :
|
||||
INLINE VertexDataBuffer::
|
||||
VertexDataBuffer(const VertexDataBuffer ©) :
|
||||
_resident_data(NULL),
|
||||
_size(0)
|
||||
_size(0),
|
||||
_reserved_size(0)
|
||||
{
|
||||
(*this) = copy;
|
||||
}
|
||||
@ -81,6 +85,7 @@ get_read_pointer(bool force) const {
|
||||
}
|
||||
|
||||
nassertr(_block != (VertexDataBlock *)NULL, NULL);
|
||||
nassertr(_reserved_size >= _size, NULL);
|
||||
|
||||
// We don't necessarily need to page the buffer all the way into
|
||||
// independent status; it's sufficient just to return the block's
|
||||
@ -97,9 +102,10 @@ INLINE unsigned char *VertexDataBuffer::
|
||||
get_write_pointer() {
|
||||
LightMutexHolder holder(_lock);
|
||||
|
||||
if (_resident_data == (unsigned char *)NULL && _size != 0) {
|
||||
if (_resident_data == (unsigned char *)NULL && _reserved_size != 0) {
|
||||
do_page_in();
|
||||
}
|
||||
nassertr(_reserved_size >= _size, NULL);
|
||||
return _resident_data;
|
||||
}
|
||||
|
||||
@ -114,17 +120,58 @@ get_size() const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::clean_realloc
|
||||
// Function: VertexDataBuffer::get_reserved_size
|
||||
// Access: Public
|
||||
// Description: Changes the size of the buffer, preserving its data
|
||||
// (except for any data beyond the new end of the
|
||||
// buffer, if the buffer is being reduced). If the
|
||||
// buffer is expanded, the new data is uninitialized.
|
||||
// Description: Returns the total number of bytes "reserved" in the
|
||||
// buffer. This may be greater than or equal to
|
||||
// get_size(). If it is greater, the additional bytes
|
||||
// are extra unused bytes in the buffer, and this
|
||||
// indicates the maximum value that may be passed to
|
||||
// set_size() without first calling one of the realloc
|
||||
// methods.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE size_t VertexDataBuffer::
|
||||
get_reserved_size() const {
|
||||
return _reserved_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::set_size
|
||||
// Access: Public
|
||||
// Description: Changes the size of the buffer. The new size must be
|
||||
// less than or equal to the "reserved" size, which can
|
||||
// only be changed via clean_realloc() or
|
||||
// unclean_realloc().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
clean_realloc(size_t size) {
|
||||
set_size(size_t size) {
|
||||
LightMutexHolder holder(_lock);
|
||||
do_clean_realloc(size);
|
||||
nassertv(size <= _reserved_size);
|
||||
|
||||
if (size != _size) {
|
||||
if (_resident_data == (unsigned char *)NULL && _reserved_size != 0) {
|
||||
do_page_in();
|
||||
}
|
||||
|
||||
_size = size;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::clean_realloc
|
||||
// Access: Public
|
||||
// Description: Changes the "reserved" size of the buffer, preserving
|
||||
// its data (except for any data beyond the new end of
|
||||
// the buffer, if the buffer is being reduced). If the
|
||||
// buffer is expanded, the new data is uninitialized.
|
||||
//
|
||||
// It is an error to set the reserved size smaller than
|
||||
// the size specified with set_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
clean_realloc(size_t reserved_size) {
|
||||
LightMutexHolder holder(_lock);
|
||||
do_clean_realloc(reserved_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -133,11 +180,14 @@ clean_realloc(size_t size) {
|
||||
// Description: Changes the size of the buffer, without regard to
|
||||
// preserving its data. The buffer may contain random
|
||||
// data after this call.
|
||||
//
|
||||
// It is an error to set the reserved size smaller than
|
||||
// the size specified with set_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
unclean_realloc(size_t size) {
|
||||
unclean_realloc(size_t reserved_size) {
|
||||
LightMutexHolder holder(_lock);
|
||||
do_unclean_realloc(size);
|
||||
do_unclean_realloc(reserved_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -147,7 +197,9 @@ unclean_realloc(size_t size) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
clear() {
|
||||
unclean_realloc(0);
|
||||
LightMutexHolder holder(_lock);
|
||||
_size = 0;
|
||||
do_unclean_realloc(0);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -165,27 +217,3 @@ page_out(VertexDataBook &book) {
|
||||
LightMutexHolder holder(_lock);
|
||||
do_page_out(book);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::swap
|
||||
// Access: Public
|
||||
// Description: Swaps the data buffers between this one and the other
|
||||
// one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void VertexDataBuffer::
|
||||
swap(VertexDataBuffer &other) {
|
||||
LightMutexHolder holder(_lock);
|
||||
LightMutexHolder holder2(other._lock);
|
||||
|
||||
unsigned char *resident_data = _resident_data;
|
||||
size_t size = _size;
|
||||
PT(VertexDataBlock) block = _block;
|
||||
|
||||
_resident_data = other._resident_data;
|
||||
_size = other._size;
|
||||
_block = other._block;
|
||||
|
||||
other._resident_data = resident_data;
|
||||
other._size = size;
|
||||
other._block = block;
|
||||
}
|
||||
|
@ -28,89 +28,134 @@ operator = (const VertexDataBuffer ©) {
|
||||
LightMutexHolder holder2(copy._lock);
|
||||
|
||||
if (_resident_data != (unsigned char *)NULL) {
|
||||
nassertv(_size != 0);
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
nassertv(_reserved_size != 0);
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
|
||||
PANDA_FREE_ARRAY(_resident_data);
|
||||
_resident_data = NULL;
|
||||
}
|
||||
if (copy._resident_data != (unsigned char *)NULL) {
|
||||
nassertv(copy._size != 0);
|
||||
if (copy._resident_data != (unsigned char *)NULL && copy._size != 0) {
|
||||
// We only allocate _size bytes, not the full _reserved_size
|
||||
// allocated by the original copy.
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)copy._size);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(copy._size);
|
||||
memcpy(_resident_data, copy._resident_data, copy._size);
|
||||
}
|
||||
_size = copy._size;
|
||||
_reserved_size = copy._size;
|
||||
_block = copy._block;
|
||||
nassertv(_reserved_size >= _size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::swap
|
||||
// Access: Public
|
||||
// Description: Swaps the data buffers between this one and the other
|
||||
// one.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
swap(VertexDataBuffer &other) {
|
||||
LightMutexHolder holder(_lock);
|
||||
LightMutexHolder holder2(other._lock);
|
||||
|
||||
unsigned char *resident_data = _resident_data;
|
||||
size_t size = _size;
|
||||
size_t reserved_size = _reserved_size;
|
||||
PT(VertexDataBlock) block = _block;
|
||||
|
||||
_resident_data = other._resident_data;
|
||||
_size = other._size;
|
||||
_reserved_size = other._reserved_size;
|
||||
_block = other._block;
|
||||
|
||||
other._resident_data = resident_data;
|
||||
other._size = size;
|
||||
other._reserved_size = reserved_size;
|
||||
other._block = block;
|
||||
nassertv(_reserved_size >= _size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::do_clean_realloc
|
||||
// Access: Private
|
||||
// Description: Changes the size of the buffer, preserving its data
|
||||
// (except for any data beyond the new end of the
|
||||
// buffer, if the buffer is being reduced). If the
|
||||
// Description: Changes the reserved size of the buffer, preserving
|
||||
// its data (except for any data beyond the new end of
|
||||
// the buffer, if the buffer is being reduced). If the
|
||||
// buffer is expanded, the new data is uninitialized.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
do_clean_realloc(size_t size) {
|
||||
if (size != _size) {
|
||||
if (size == 0) {
|
||||
do_unclean_realloc(size);
|
||||
do_clean_realloc(size_t reserved_size) {
|
||||
if (reserved_size != _reserved_size) {
|
||||
if (reserved_size == 0 || _size == 0) {
|
||||
do_unclean_realloc(reserved_size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< this << ".clean_realloc(" << reserved_size << ")\n";
|
||||
}
|
||||
|
||||
// Page in if we're currently paged out.
|
||||
if (_size != 0 && _resident_data == (unsigned char *)NULL) {
|
||||
if (_reserved_size != 0 && _resident_data == (unsigned char *)NULL) {
|
||||
do_page_in();
|
||||
}
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size - (int)_size);
|
||||
if (_size == 0) {
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size - (int)_reserved_size);
|
||||
if (_reserved_size == 0) {
|
||||
nassertv(_resident_data == (unsigned char *)NULL);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(size);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
|
||||
} else {
|
||||
nassertv(_resident_data != (unsigned char *)NULL);
|
||||
_resident_data = (unsigned char *)PANDA_REALLOC_ARRAY(_resident_data, size);
|
||||
_resident_data = (unsigned char *)PANDA_REALLOC_ARRAY(_resident_data, reserved_size);
|
||||
}
|
||||
nassertv(_resident_data != (unsigned char *)NULL);
|
||||
_size = size;
|
||||
_reserved_size = reserved_size;
|
||||
}
|
||||
|
||||
_size = min(_size, _reserved_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexDataBuffer::do_unclean_realloc
|
||||
// Access: Private
|
||||
// Description: Changes the size of the buffer, without regard to
|
||||
// preserving its data. The buffer may contain random
|
||||
// data after this call.
|
||||
// Description: Changes the reserved size of the buffer, without
|
||||
// regard to preserving its data. This implicitly
|
||||
// resets the size to 0.
|
||||
//
|
||||
// Assumes the lock is already held.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
do_unclean_realloc(size_t size) {
|
||||
if (size != _size || _resident_data == (unsigned char *)NULL) {
|
||||
do_unclean_realloc(size_t reserved_size) {
|
||||
if (reserved_size != _reserved_size || _resident_data == (unsigned char *)NULL) {
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< this << ".unclean_realloc(" << reserved_size << ")\n";
|
||||
}
|
||||
|
||||
// If we're paged out, discard the page.
|
||||
_block = NULL;
|
||||
|
||||
if (_resident_data != (unsigned char *)NULL) {
|
||||
nassertv(_size != 0);
|
||||
nassertv(_reserved_size != 0);
|
||||
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
|
||||
PANDA_FREE_ARRAY(_resident_data);
|
||||
_resident_data = NULL;
|
||||
_size = 0;
|
||||
_reserved_size = 0;
|
||||
}
|
||||
|
||||
if (size != 0) {
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)size);
|
||||
if (reserved_size != 0) {
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)reserved_size);
|
||||
nassertv(_resident_data == (unsigned char *)NULL);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(size);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(reserved_size);
|
||||
}
|
||||
|
||||
_size = size;
|
||||
_reserved_size = reserved_size;
|
||||
}
|
||||
|
||||
_size = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -127,21 +172,36 @@ do_unclean_realloc(size_t size) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
do_page_out(VertexDataBook &book) {
|
||||
if (_block != (VertexDataBlock *)NULL || _size == 0) {
|
||||
if (_block != (VertexDataBlock *)NULL || _reserved_size == 0) {
|
||||
// We're already paged out.
|
||||
return;
|
||||
}
|
||||
nassertv(_resident_data != (unsigned char *)NULL);
|
||||
|
||||
_block = book.alloc(_size);
|
||||
nassertv(_block != (VertexDataBlock *)NULL);
|
||||
unsigned char *pointer = _block->get_pointer(true);
|
||||
nassertv(pointer != (unsigned char *)NULL);
|
||||
memcpy(pointer, _resident_data, _size);
|
||||
if (_size == 0) {
|
||||
// It's an empty buffer. Just deallocate it; don't bother to
|
||||
// create a block.
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
|
||||
PANDA_FREE_ARRAY(_resident_data);
|
||||
_resident_data = NULL;
|
||||
_reserved_size = 0;
|
||||
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
PANDA_FREE_ARRAY(_resident_data);
|
||||
_resident_data = NULL;
|
||||
} else {
|
||||
// It's a nonempty buffer, so write _size bytes (but not the full
|
||||
// _reserved_size bytes) to a block.
|
||||
_block = book.alloc(_size);
|
||||
nassertv(_block != (VertexDataBlock *)NULL);
|
||||
unsigned char *pointer = _block->get_pointer(true);
|
||||
nassertv(pointer != (unsigned char *)NULL);
|
||||
memcpy(pointer, _resident_data, _size);
|
||||
|
||||
get_class_type().dec_memory_usage(TypeHandle::MC_array, (int)_reserved_size);
|
||||
PANDA_FREE_ARRAY(_resident_data);
|
||||
_resident_data = NULL;
|
||||
|
||||
_reserved_size = _size;
|
||||
}
|
||||
nassertv(_reserved_size >= _size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -155,12 +215,13 @@ do_page_out(VertexDataBook &book) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexDataBuffer::
|
||||
do_page_in() {
|
||||
if (_resident_data != (unsigned char *)NULL || _size == 0) {
|
||||
if (_resident_data != (unsigned char *)NULL || _reserved_size == 0) {
|
||||
// We're already paged in.
|
||||
return;
|
||||
}
|
||||
|
||||
nassertv(_block != (VertexDataBlock *)NULL);
|
||||
nassertv(_reserved_size == _size);
|
||||
|
||||
get_class_type().inc_memory_usage(TypeHandle::MC_array, (int)_size);
|
||||
_resident_data = (unsigned char *)PANDA_MALLOC_ARRAY(_size);
|
||||
|
@ -33,14 +33,16 @@
|
||||
//
|
||||
// independent - the buffer's memory is resident, and
|
||||
// owned by the VertexDataBuffer object itself (in
|
||||
// _resident_data).
|
||||
// _resident_data). In this state, _reserved_size might
|
||||
// be greater than or equal to _size.
|
||||
//
|
||||
// paged - the buffer's memory is owned by a
|
||||
// VertexDataBlock. That block might itself be
|
||||
// resident, compressed, or paged to disk. If it is
|
||||
// resident, the memory may still be accessed directly
|
||||
// from the block. However, this memory is considered
|
||||
// read-only.
|
||||
// read-only. In this state, _reserved_size will always
|
||||
// equal _size.
|
||||
//
|
||||
// VertexDataBuffers start out in independent state.
|
||||
// They get moved to paged state when their owning
|
||||
@ -68,13 +70,15 @@ public:
|
||||
INLINE unsigned char *get_write_pointer();
|
||||
|
||||
INLINE size_t get_size() const;
|
||||
INLINE void clean_realloc(size_t size);
|
||||
INLINE void unclean_realloc(size_t size);
|
||||
INLINE size_t get_reserved_size() const;
|
||||
INLINE void set_size(size_t size);
|
||||
INLINE void clean_realloc(size_t reserved_size);
|
||||
INLINE void unclean_realloc(size_t reserved_size);
|
||||
INLINE void clear();
|
||||
|
||||
INLINE void page_out(VertexDataBook &book);
|
||||
|
||||
INLINE void swap(VertexDataBuffer &other);
|
||||
void swap(VertexDataBuffer &other);
|
||||
|
||||
private:
|
||||
void do_clean_realloc(size_t size);
|
||||
@ -85,6 +89,7 @@ private:
|
||||
|
||||
unsigned char *_resident_data;
|
||||
size_t _size;
|
||||
size_t _reserved_size;
|
||||
PT(VertexDataBlock) _block;
|
||||
LightMutex _lock;
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include "datagramIterator.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "geom.h"
|
||||
#include "geomLinestrips.h"
|
||||
#include "geomLines.h"
|
||||
#include "geomTristrips.h"
|
||||
#include "geomVertexWriter.h"
|
||||
#include "boundingSphere.h"
|
||||
@ -352,27 +352,27 @@ void RopeNode::
|
||||
render_thread(CullTraverser *trav, CullTraverserData &data,
|
||||
NurbsCurveResult *result) const {
|
||||
CurveSegments curve_segments;
|
||||
get_connected_segments(curve_segments, result);
|
||||
int num_curve_verts = get_connected_segments(curve_segments, result);
|
||||
|
||||
// Now we have stored one or more sequences of vertices down the
|
||||
// center strips. Go back through and calculate the vertices on
|
||||
// either side.
|
||||
// thread. These map directly to primitive vertices.
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
("rope", get_format(false), Geom::UH_stream);
|
||||
|
||||
compute_thread_vertices(vdata, curve_segments);
|
||||
|
||||
PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
|
||||
CurveSegments::const_iterator si;
|
||||
for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
|
||||
const CurveSegment &segment = (*si);
|
||||
|
||||
strip->add_next_vertices(segment.size());
|
||||
strip->close_primitive();
|
||||
compute_thread_vertices(vdata, curve_segments, num_curve_verts);
|
||||
|
||||
// We use GeomLines instead of GeomLinestrips, since that can more
|
||||
// easily be rendered directly.
|
||||
PT(GeomLines) lines = new GeomLines(Geom::UH_stream);
|
||||
lines->reserve_num_vertices((num_curve_verts - 1) * 2);
|
||||
|
||||
for (int vi = 0; vi < num_curve_verts - 1; ++vi) {
|
||||
lines->add_vertex(vi);
|
||||
lines->add_vertex(vi + 1);
|
||||
lines->close_primitive();
|
||||
}
|
||||
|
||||
PT(Geom) geom = new Geom(vdata);
|
||||
geom->add_primitive(strip);
|
||||
geom->add_primitive(lines);
|
||||
|
||||
CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
|
||||
CPT(RenderState) state = data._state->add_attrib(thick);
|
||||
@ -402,7 +402,7 @@ void RopeNode::
|
||||
render_tape(CullTraverser *trav, CullTraverserData &data,
|
||||
NurbsCurveResult *result) const {
|
||||
CurveSegments curve_segments;
|
||||
get_connected_segments(curve_segments, result);
|
||||
int num_curve_verts = get_connected_segments(curve_segments, result);
|
||||
|
||||
// Now we have stored one or more sequences of vertices down the
|
||||
// center strips. Go back through and calculate the vertices on
|
||||
@ -411,8 +411,10 @@ render_tape(CullTraverser *trav, CullTraverserData &data,
|
||||
("rope", get_format(false), Geom::UH_stream);
|
||||
|
||||
compute_billboard_vertices(vdata, -get_tube_up(),
|
||||
curve_segments, result);
|
||||
|
||||
curve_segments, num_curve_verts, result);
|
||||
|
||||
// Since this will be a nonindexed primitive, no need to pre-reserve
|
||||
// the number of vertices.
|
||||
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
|
||||
CurveSegments::const_iterator si;
|
||||
for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
|
||||
@ -459,7 +461,7 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
|
||||
LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
|
||||
|
||||
CurveSegments curve_segments;
|
||||
get_connected_segments(curve_segments, result);
|
||||
int num_curve_verts = get_connected_segments(curve_segments, result);
|
||||
|
||||
// Now we have stored one or more sequences of vertices down the
|
||||
// center strips. Go back through and calculate the vertices on
|
||||
@ -468,8 +470,10 @@ render_billboard(CullTraverser *trav, CullTraverserData &data,
|
||||
("rope", get_format(false), Geom::UH_stream);
|
||||
|
||||
compute_billboard_vertices(vdata, camera_vec,
|
||||
curve_segments, result);
|
||||
curve_segments, num_curve_verts, result);
|
||||
|
||||
// Since this will be a nonindexed primitive, no need to pre-reserve
|
||||
// the number of vertices.
|
||||
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
|
||||
CurveSegments::const_iterator si;
|
||||
for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
|
||||
@ -508,7 +512,7 @@ void RopeNode::
|
||||
render_tube(CullTraverser *trav, CullTraverserData &data,
|
||||
NurbsCurveResult *result) const {
|
||||
CurveSegments curve_segments;
|
||||
get_connected_segments(curve_segments, result);
|
||||
int num_curve_verts = get_connected_segments(curve_segments, result);
|
||||
|
||||
// Now, we build up a table of vertices, in a series of rings
|
||||
// around the circumference of the tube.
|
||||
@ -520,11 +524,13 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
|
||||
("rope", get_format(true), Geom::UH_stream);
|
||||
|
||||
compute_tube_vertices(vdata, num_verts_per_slice,
|
||||
curve_segments, result);
|
||||
curve_segments, num_curve_verts, result);
|
||||
|
||||
// Finally, go through and build up the index array, to tie all the
|
||||
// triangle strips together. This is difficult to pre-calculate the
|
||||
// number of vertices we'll use, so we'll just let it dynamically
|
||||
// allocate.
|
||||
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
|
||||
// Finally, go through build up the index array, to tie all the
|
||||
// triangle strips together.
|
||||
int vi = 0;
|
||||
CurveSegments::const_iterator si;
|
||||
for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
|
||||
@ -571,10 +577,15 @@ render_tube(CullTraverser *trav, CullTraverserData &data,
|
||||
// segments from the NurbsCurveEvaluator into a single
|
||||
// CurveSegment, if they happen to be connected (as most
|
||||
// will be).
|
||||
//
|
||||
// The return value is the total number of points across
|
||||
// all segments.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RopeNode::
|
||||
int RopeNode::
|
||||
get_connected_segments(RopeNode::CurveSegments &curve_segments,
|
||||
const NurbsCurveResult *result) const {
|
||||
int num_curve_verts = 0;
|
||||
|
||||
int num_verts = get_num_subdiv() + 1;
|
||||
int num_segments = result->get_num_segments();
|
||||
bool use_vertex_color = get_use_vertex_color();
|
||||
@ -610,6 +621,7 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
|
||||
}
|
||||
|
||||
curve_segment->push_back(vtx);
|
||||
++num_curve_verts;
|
||||
}
|
||||
|
||||
// Store all the remaining points in this segment.
|
||||
@ -631,10 +643,13 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
|
||||
}
|
||||
|
||||
curve_segment->push_back(vtx);
|
||||
++num_curve_verts;
|
||||
|
||||
last_point = vtx._p;
|
||||
}
|
||||
}
|
||||
|
||||
return num_curve_verts;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -646,7 +661,10 @@ get_connected_segments(RopeNode::CurveSegments &curve_segments,
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void RopeNode::
|
||||
compute_thread_vertices(GeomVertexData *vdata,
|
||||
const RopeNode::CurveSegments &curve_segments) const {
|
||||
const RopeNode::CurveSegments &curve_segments,
|
||||
int num_curve_verts) const {
|
||||
vdata->set_num_rows(num_curve_verts);
|
||||
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
@ -678,6 +696,8 @@ compute_thread_vertices(GeomVertexData *vdata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nassertv(vdata->get_num_rows() == num_curve_verts);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -691,7 +711,11 @@ void RopeNode::
|
||||
compute_billboard_vertices(GeomVertexData *vdata,
|
||||
const LVector3f &camera_vec,
|
||||
const RopeNode::CurveSegments &curve_segments,
|
||||
int num_curve_verts,
|
||||
NurbsCurveResult *result) const {
|
||||
int expected_num_verts = num_curve_verts * 2;
|
||||
vdata->set_num_rows(expected_num_verts);
|
||||
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
@ -741,6 +765,8 @@ compute_billboard_vertices(GeomVertexData *vdata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nassertv(vdata->get_num_rows() == expected_num_verts);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
@ -754,12 +780,8 @@ void RopeNode::
|
||||
compute_tube_vertices(GeomVertexData *vdata,
|
||||
int &num_verts_per_slice,
|
||||
const RopeNode::CurveSegments &curve_segments,
|
||||
int num_curve_verts,
|
||||
NurbsCurveResult *result) const {
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter normal(vdata, InternalName::get_normal());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
int num_slices = get_num_slices();
|
||||
num_verts_per_slice = num_slices;
|
||||
|
||||
@ -780,6 +802,14 @@ compute_tube_vertices(GeomVertexData *vdata,
|
||||
++num_verts_per_slice;
|
||||
}
|
||||
|
||||
int expected_num_verts = num_curve_verts * num_verts_per_slice;
|
||||
vdata->set_num_rows(expected_num_verts);
|
||||
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter normal(vdata, InternalName::get_normal());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
LVector3f up = get_tube_up();
|
||||
|
||||
float dist = 0.0f;
|
||||
@ -827,6 +857,8 @@ compute_tube_vertices(GeomVertexData *vdata,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nassertv(vdata->get_num_rows() == expected_num_verts);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
@ -173,18 +173,21 @@ private:
|
||||
typedef pvector<CurveVertex> CurveSegment;
|
||||
typedef pvector<CurveSegment> CurveSegments;
|
||||
|
||||
void get_connected_segments(CurveSegments &curve_segments,
|
||||
const NurbsCurveResult *result) const;
|
||||
int get_connected_segments(CurveSegments &curve_segments,
|
||||
const NurbsCurveResult *result) const;
|
||||
|
||||
void compute_thread_vertices(GeomVertexData *vdata,
|
||||
const CurveSegments &curve_segments) const;
|
||||
const CurveSegments &curve_segments,
|
||||
int num_curve_verts) const;
|
||||
void compute_billboard_vertices(GeomVertexData *vdata,
|
||||
const LVector3f &camera_vec,
|
||||
const CurveSegments &curve_segments,
|
||||
int num_curve_verts,
|
||||
NurbsCurveResult *result) const;
|
||||
void compute_tube_vertices(GeomVertexData *vdata,
|
||||
int &num_verts_per_slice,
|
||||
const CurveSegments &curve_segments,
|
||||
int num_curve_verts,
|
||||
NurbsCurveResult *result) const;
|
||||
|
||||
static void compute_tangent(LVector3f &tangent, const CurveSegment &segment,
|
||||
|
@ -300,18 +300,18 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
|
||||
}
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
("sheet", format, Geom::UH_stream);
|
||||
int expected_num_vertices = num_u_segments * (num_u_verts + 1) * num_v_segments * num_v_verts;
|
||||
vdata->reserve_num_rows(expected_num_vertices);
|
||||
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter normal(vdata, InternalName::get_normal());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
|
||||
|
||||
for (int ui = 0; ui < num_u_segments; ui++) {
|
||||
for (int uni = 0; uni < num_u_verts; uni++) {
|
||||
for (int uni = 0; uni <= num_u_verts; uni++) {
|
||||
float u0 = (float)uni / (float)num_u_verts;
|
||||
float u1 = (float)(uni + 1) / (float)num_u_verts;
|
||||
float u0_tc = result->get_segment_u(ui, u0);
|
||||
float u1_tc = result->get_segment_u(ui, u1);
|
||||
|
||||
for (int vi = 0; vi < num_v_segments; vi++) {
|
||||
for (int vni = 0; vni < num_v_verts; vni++) {
|
||||
@ -326,26 +326,44 @@ render_sheet(CullTraverser *trav, CullTraverserData &data,
|
||||
normal.add_data3f(norm);
|
||||
texcoord.add_data2f(u0_tc, v_tc);
|
||||
|
||||
result->eval_segment_point(ui, vi, u1, v, point);
|
||||
result->eval_segment_normal(ui, vi, u1, v, norm);
|
||||
vertex.add_data3f(point);
|
||||
normal.add_data3f(norm);
|
||||
texcoord.add_data2f(u1_tc, v_tc);
|
||||
|
||||
if (use_vertex_color) {
|
||||
Colorf c0, c1;
|
||||
Colorf c0;
|
||||
result->eval_segment_extended_points(ui, vi, u0, v, 0, &c0[0], 4);
|
||||
result->eval_segment_extended_points(ui, vi, u1, v, 0, &c1[0], 4);
|
||||
|
||||
color.add_data4f(c0);
|
||||
color.add_data4f(c1);
|
||||
}
|
||||
}
|
||||
strip->add_next_vertices(num_v_verts * 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
nassertv(vdata->get_num_rows() == expected_num_vertices);
|
||||
|
||||
PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
|
||||
|
||||
int expected_num_tristrips = num_u_segments * num_u_verts * num_v_segments;
|
||||
int expected_verts_per_tristrip = num_v_verts * 2;
|
||||
|
||||
int expected_prim_vertices = (expected_num_tristrips - 1) * (expected_verts_per_tristrip + strip->get_num_unused_vertices_per_primitive()) + expected_verts_per_tristrip;
|
||||
|
||||
strip->reserve_num_vertices(expected_prim_vertices);
|
||||
|
||||
int verts_per_row = num_v_segments * num_v_verts;
|
||||
|
||||
for (int ui = 0; ui < num_u_segments; ui++) {
|
||||
for (int uni = 0; uni < num_u_verts; uni++) {
|
||||
int row_start_index = ((ui * (num_u_verts + 1)) + uni) * verts_per_row;
|
||||
|
||||
for (int vi = 0; vi < num_v_segments; vi++) {
|
||||
for (int vni = 0; vni < num_v_verts; vni++) {
|
||||
int vert_index_0 = row_start_index + (vi * num_v_verts) + vni;
|
||||
int vert_index_1 = vert_index_0 + verts_per_row;
|
||||
strip->add_vertex(vert_index_0);
|
||||
strip->add_vertex(vert_index_1);
|
||||
}
|
||||
strip->close_primitive();
|
||||
}
|
||||
}
|
||||
}
|
||||
nassertv(strip->get_num_vertices() == expected_prim_vertices);
|
||||
|
||||
PT(Geom) geom = new Geom(vdata);
|
||||
geom->add_primitive(strip);
|
||||
|
@ -1584,6 +1584,7 @@ draw_underscore(TextAssembler::PlacedGlyphs &row_placed_glyphs,
|
||||
CPT(GeomVertexFormat) format = GeomVertexFormat::get_v3cp();
|
||||
PT(GeomVertexData) vdata =
|
||||
new GeomVertexData("text", format, Geom::UH_static);
|
||||
vdata->reserve_num_rows(2);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter color(vdata, InternalName::get_color());
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user