mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
some animation optimizations
This commit is contained in:
parent
5e5d8f7e17
commit
7e8737dd3d
@ -800,6 +800,53 @@ transform(const LMatrix4d &mat) {
|
||||
}
|
||||
|
||||
|
||||
// A function object for sort_by_external_index(), below.
|
||||
class SortByExternalIndex {
|
||||
public:
|
||||
bool operator () (EggVertex *a, EggVertex *b) const {
|
||||
int ai = a->get_external_index();
|
||||
int bi = b->get_external_index();
|
||||
if (ai != bi) {
|
||||
return ai < bi;
|
||||
}
|
||||
return a->get_index() < b->get_index();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::sort_by_external_index
|
||||
// Access: Published
|
||||
// Description: Re-orders (and re-numbers) the vertices in this
|
||||
// vertex pool so that they appear in increasing order
|
||||
// by the optional external_index that has been assigned
|
||||
// to each vertex.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void EggVertexPool::
|
||||
sort_by_external_index() {
|
||||
// Copy the vertices into a vector for sorting.
|
||||
typedef pvector<EggVertex *> SortedVertices;
|
||||
SortedVertices sorted_vertices;
|
||||
sorted_vertices.reserve(size());
|
||||
iterator i;
|
||||
for (i = begin(); i != end(); ++i) {
|
||||
sorted_vertices.push_back(*i);
|
||||
}
|
||||
|
||||
::sort(sorted_vertices.begin(), sorted_vertices.end(), SortByExternalIndex());
|
||||
|
||||
// Now reassign the indices, and copy them into a new index map.
|
||||
IndexVertices new_index_vertices;
|
||||
int vi;
|
||||
for (vi = 0; vi < (int)sorted_vertices.size(); ++vi) {
|
||||
EggVertex *vertex = sorted_vertices[vi];
|
||||
vertex->_index = vi;
|
||||
new_index_vertices[vi] = vertex;
|
||||
}
|
||||
|
||||
// Finally, assign the new index map.
|
||||
_index_vertices.swap(new_index_vertices);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggVertexPool::write
|
||||
// Access: Public
|
||||
|
@ -133,6 +133,7 @@ PUBLISHED:
|
||||
void add_unused_vertices_to_prim(EggPrimitive *prim);
|
||||
|
||||
void transform(const LMatrix4d &mat);
|
||||
void sort_by_external_index();
|
||||
|
||||
void write(ostream &out, int indent_level) const;
|
||||
|
||||
|
@ -170,13 +170,20 @@ ConfigVariableBool egg_preload_simple_textures
|
||||
"either this or preload-simple-textures is true."));
|
||||
|
||||
ConfigVariableDouble egg_vertex_membership_quantize
|
||||
("egg-vertex-membership-quantize", 0.01,
|
||||
("egg-vertex-membership-quantize", 0.1,
|
||||
PRC_DESC("Specifies the nearest amount to round each vertex joint "
|
||||
"membership value when loading an egg file. This affects animated "
|
||||
"egg files only. There is a substantial runtime "
|
||||
"performance advantage for reducing trivial differences in joint "
|
||||
"membership. Set this to 0 to leave joint membership as it is."));
|
||||
|
||||
ConfigVariableInt egg_vertex_max_num_joints
|
||||
("egg-vertex-max-num-joints", 4,
|
||||
PRC_DESC("Specifies the maximum number of distinct joints that are allowed "
|
||||
"to control any one vertex. If a vertex requests assignment to "
|
||||
"more than this number of joints, the joints with the lesser membership "
|
||||
"value are ignored. Set this to -1 to allow any number of joints."));
|
||||
|
||||
ConfigureFn(config_egg2pg) {
|
||||
init_libegg2pg();
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ extern EXPCL_PANDAEGG ConfigVariableInt egg_max_indices;
|
||||
extern EXPCL_PANDAEGG ConfigVariableBool egg_emulate_bface;
|
||||
extern EXPCL_PANDAEGG ConfigVariableBool egg_preload_simple_textures;
|
||||
extern EXPCL_PANDAEGG ConfigVariableDouble egg_vertex_membership_quantize;
|
||||
extern EXPCL_PANDAEGG ConfigVariableInt egg_vertex_max_num_joints;
|
||||
|
||||
extern EXPCL_PANDAEGG void init_libegg2pg();
|
||||
|
||||
|
@ -379,6 +379,20 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
|
||||
// pools as if they contain a combination of multiple colors.
|
||||
has_overall_color = false;
|
||||
}
|
||||
|
||||
PT(TransformBlendTable) blend_table;
|
||||
if (is_dynamic) {
|
||||
// Dynamic vertex pools will require a TransformBlendTable to
|
||||
// indicate how the vertices are to be animated.
|
||||
blend_table = make_blend_table(vertex_pool, egg_bin, character_maker);
|
||||
|
||||
// Now that we've created the blend table, we can re-order the
|
||||
// vertices in the pool to efficiently group vertices together
|
||||
// that will share the same transform matrix. (We have to
|
||||
// re-order them before we create primitives, below, because
|
||||
// this will change the vertex index numbers.)
|
||||
vertex_pool->sort_by_external_index();
|
||||
}
|
||||
|
||||
// Create a handful of GeomPrimitives corresponding to the various
|
||||
// types of primitives that reference this vertex pool.
|
||||
@ -400,10 +414,10 @@ make_polyset(EggBin *egg_bin, PandaNode *parent, const LMatrix4d *transform,
|
||||
} else {
|
||||
mat = egg_bin->get_vertex_to_node();
|
||||
}
|
||||
|
||||
|
||||
// Now convert this vertex pool to a GeomVertexData.
|
||||
PT(GeomVertexData) vertex_data =
|
||||
make_vertex_data(render_state, vertex_pool, egg_bin, mat,
|
||||
make_vertex_data(render_state, vertex_pool, egg_bin, mat, blend_table,
|
||||
is_dynamic, character_maker, has_overall_color);
|
||||
nassertv(vertex_data != (GeomVertexData *)NULL);
|
||||
|
||||
@ -2185,7 +2199,7 @@ check_for_polysets(EggGroup *egg_group, bool &all_polysets, bool &any_hidden) {
|
||||
PT(GeomVertexData) EggLoader::
|
||||
make_vertex_data(const EggRenderState *render_state,
|
||||
EggVertexPool *vertex_pool, EggNode *primitive_home,
|
||||
const LMatrix4d &transform,
|
||||
const LMatrix4d &transform, TransformBlendTable *blend_table,
|
||||
bool is_dynamic, CharacterMaker *character_maker,
|
||||
bool ignore_color) {
|
||||
VertexPoolTransform vpt;
|
||||
@ -2255,7 +2269,6 @@ make_vertex_data(const EggRenderState *render_state,
|
||||
|
||||
PT(GeomVertexFormat) temp_format = new GeomVertexFormat(array_format);
|
||||
|
||||
PT(TransformBlendTable) blend_table;
|
||||
PT(SliderTable) slider_table;
|
||||
string name = _data->get_egg_filename().get_basename_wo_extension();
|
||||
|
||||
@ -2271,9 +2284,6 @@ make_vertex_data(const EggRenderState *render_state,
|
||||
animation.set_panda();
|
||||
temp_format->set_animation(animation);
|
||||
|
||||
blend_table = new TransformBlendTable;
|
||||
blend_table->set_rows(SparseArray::lower_on(vertex_pool->size()));
|
||||
|
||||
PT(GeomVertexArrayFormat) anim_array_format = new GeomVertexArrayFormat;
|
||||
anim_array_format->add_column
|
||||
(InternalName::get_transform_blend(), 1,
|
||||
@ -2477,34 +2487,7 @@ make_vertex_data(const EggRenderState *render_state,
|
||||
}
|
||||
|
||||
if (is_dynamic) {
|
||||
// Figure out the transforms affecting this particular vertex.
|
||||
TransformBlend blend;
|
||||
if (vertex->gref_size() == 0) {
|
||||
// If the vertex has no explicit membership, it belongs right
|
||||
// where it is.
|
||||
PT(VertexTransform) vt = character_maker->egg_to_transform(primitive_home);
|
||||
nassertr(vt != (VertexTransform *)NULL, vertex_data);
|
||||
blend.add_transform(vt, 1.0f);
|
||||
} else {
|
||||
// If the vertex does have an explicit membership, ignore its
|
||||
// parentage and assign it where it wants to be.
|
||||
double quantize = egg_vertex_membership_quantize;
|
||||
EggVertex::GroupRef::const_iterator gri;
|
||||
for (gri = vertex->gref_begin(); gri != vertex->gref_end(); ++gri) {
|
||||
EggGroup *egg_joint = (*gri);
|
||||
double membership = egg_joint->get_vertex_membership(vertex);
|
||||
if (quantize != 0.0) {
|
||||
membership = cfloor(membership / quantize + 0.5) * quantize;
|
||||
}
|
||||
|
||||
PT(VertexTransform) vt = character_maker->egg_to_transform(egg_joint);
|
||||
nassertr(vt != (VertexTransform *)NULL, vertex_data);
|
||||
blend.add_transform(vt, membership);
|
||||
}
|
||||
}
|
||||
blend.normalize_weights();
|
||||
|
||||
int table_index = blend_table->add_blend(blend);
|
||||
int table_index = vertex->get_external_index();
|
||||
gvw.set_column(InternalName::get_transform_blend());
|
||||
gvw.set_data1i(table_index);
|
||||
}
|
||||
@ -2518,6 +2501,62 @@ make_vertex_data(const EggRenderState *render_state,
|
||||
return vertex_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::make_blend_table
|
||||
// Access: Private
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(TransformBlendTable) EggLoader::
|
||||
make_blend_table(EggVertexPool *vertex_pool, EggNode *primitive_home,
|
||||
CharacterMaker *character_maker) {
|
||||
PT(TransformBlendTable) blend_table;
|
||||
blend_table = new TransformBlendTable;
|
||||
blend_table->set_rows(SparseArray::lower_on(vertex_pool->size()));
|
||||
|
||||
EggVertexPool::const_iterator vi;
|
||||
for (vi = vertex_pool->begin(); vi != vertex_pool->end(); ++vi) {
|
||||
EggVertex *vertex = (*vi);
|
||||
|
||||
// Figure out the transforms affecting this particular vertex.
|
||||
TransformBlend blend;
|
||||
if (vertex->gref_size() == 0) {
|
||||
// If the vertex has no explicit membership, it belongs right
|
||||
// where it is.
|
||||
PT(VertexTransform) vt = character_maker->egg_to_transform(primitive_home);
|
||||
nassertr(vt != (VertexTransform *)NULL, NULL);
|
||||
blend.add_transform(vt, 1.0f);
|
||||
} else {
|
||||
// If the vertex does have an explicit membership, ignore its
|
||||
// parentage and assign it where it wants to be.
|
||||
double quantize = egg_vertex_membership_quantize;
|
||||
EggVertex::GroupRef::const_iterator gri;
|
||||
for (gri = vertex->gref_begin(); gri != vertex->gref_end(); ++gri) {
|
||||
EggGroup *egg_joint = (*gri);
|
||||
double membership = egg_joint->get_vertex_membership(vertex);
|
||||
if (quantize != 0.0) {
|
||||
membership = cfloor(membership / quantize + 0.5) * quantize;
|
||||
}
|
||||
|
||||
PT(VertexTransform) vt = character_maker->egg_to_transform(egg_joint);
|
||||
nassertr(vt != (VertexTransform *)NULL, NULL);
|
||||
blend.add_transform(vt, membership);
|
||||
}
|
||||
}
|
||||
if (egg_vertex_max_num_joints >= 0) {
|
||||
blend.limit_transforms(egg_vertex_max_num_joints);
|
||||
}
|
||||
blend.normalize_weights();
|
||||
|
||||
int table_index = blend_table->add_blend(blend);
|
||||
|
||||
// We take advantage of the "external index" field of the
|
||||
// EggVertex to temporarily store the transform blend index.
|
||||
vertex->set_external_index(table_index);
|
||||
}
|
||||
|
||||
return blend_table;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: EggLoader::record_morph
|
||||
// Access: Private
|
||||
|
@ -143,8 +143,11 @@ private:
|
||||
bool &any_hidden);
|
||||
PT(GeomVertexData) make_vertex_data
|
||||
(const EggRenderState *render_state, EggVertexPool *vertex_pool,
|
||||
EggNode *primitive_home, const LMatrix4d &transform, bool is_dynamic,
|
||||
CharacterMaker *character_maker, bool ignore_color);
|
||||
EggNode *primitive_home, const LMatrix4d &transform, TransformBlendTable *blend_table,
|
||||
bool is_dynamic, CharacterMaker *character_maker, bool ignore_color);
|
||||
PT(TransformBlendTable) make_blend_table
|
||||
(EggVertexPool *vertex_bool, EggNode *primitive_home,
|
||||
CharacterMaker *character_maker);
|
||||
void record_morph
|
||||
(GeomVertexArrayFormat *array_format,
|
||||
CharacterMaker *character_maker, const string &morph_name,
|
||||
|
@ -35,6 +35,7 @@ PStatCollector GeomVertexData::_scale_color_pcollector("*:Munge:Scale color");
|
||||
PStatCollector GeomVertexData::_set_color_pcollector("*:Munge:Set color");
|
||||
PStatCollector GeomVertexData::_animation_pcollector("*:Animation");
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::Default Constructor
|
||||
// Access: Private
|
||||
@ -1100,6 +1101,49 @@ clear_animated_vertices() {
|
||||
cdata->_animated_vertices.clear();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::transform_vertices
|
||||
// Access: Published
|
||||
// Description: Applies the indicated transform matrix to all of the
|
||||
// vertices in the GeomVertexData. The transform is
|
||||
// applied to all "point" and "vector" type columns
|
||||
// described in the format.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomVertexData::
|
||||
transform_vertices(const LMatrix4 &mat) {
|
||||
transform_vertices(mat, 0, get_num_rows());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::transform_vertices
|
||||
// Access: Published
|
||||
// Description: Applies the indicated transform matrix to all of the
|
||||
// vertices from begin_row up to but not including
|
||||
// end_row. The transform is applied to all "point" and
|
||||
// "vector" type columns described in the format.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomVertexData::
|
||||
transform_vertices(const LMatrix4 &mat, int begin_row, int end_row) {
|
||||
if (end_row <= begin_row) {
|
||||
// Trivial no-op.
|
||||
return;
|
||||
}
|
||||
|
||||
const GeomVertexFormat *format = get_format();
|
||||
|
||||
int ci;
|
||||
for (ci = 0; ci < format->get_num_points(); ci++) {
|
||||
GeomVertexRewriter data(this, format->get_point(ci));
|
||||
do_transform_point_column(format, data, mat, begin_row, end_row);
|
||||
}
|
||||
|
||||
for (ci = 0; ci < format->get_num_vectors(); ci++) {
|
||||
GeomVertexRewriter data(this, format->get_vector(ci));
|
||||
do_transform_vector_column(format, data, mat, begin_row, end_row);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::bytewise_copy
|
||||
// Access: Private, Static
|
||||
@ -1552,17 +1596,18 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
|
||||
// Then apply the transforms.
|
||||
CPT(TransformBlendTable) tb_table = cdata->_transform_blend_table.get_read_pointer();
|
||||
if (tb_table != (TransformBlendTable *)NULL) {
|
||||
PStatTimer timer3(_skinning_pcollector);
|
||||
|
||||
// Recompute all the blends up front, so we don't have to test
|
||||
// each one for staleness at each vertex.
|
||||
int num_blends = tb_table->get_num_blends();
|
||||
int bi;
|
||||
for (bi = 0; bi < num_blends; bi++) {
|
||||
tb_table->get_blend(bi).update_blend(current_thread);
|
||||
{
|
||||
PStatTimer timer4(_blends_pcollector);
|
||||
int num_blends = tb_table->get_num_blends();
|
||||
for (int bi = 0; bi < num_blends; bi++) {
|
||||
tb_table->get_blend(bi).update_blend(current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
// Now go through and apply the transforms.
|
||||
PStatTimer timer3(_skinning_pcollector);
|
||||
|
||||
const SparseArray &rows = tb_table->get_rows();
|
||||
int num_subranges = rows.get_num_subranges();
|
||||
@ -1577,8 +1622,7 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
|
||||
|
||||
CPT(GeomVertexArrayFormat) blend_array_format = orig_format->get_array(blend_array_index);
|
||||
|
||||
if (blend_array_format->get_num_columns() == 1 &&
|
||||
blend_array_format->get_stride() == 2 &&
|
||||
if (blend_array_format->get_stride() == 2 &&
|
||||
blend_array_format->get_column(0)->get_component_bytes() == 2) {
|
||||
// The blend indices are a table of ushorts. Optimize this
|
||||
// common case.
|
||||
@ -1588,98 +1632,80 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
|
||||
int ci;
|
||||
for (ci = 0; ci < new_format->get_num_points(); ci++) {
|
||||
GeomVertexRewriter data(new_data, new_format->get_point(ci));
|
||||
const GeomVertexColumn *data_column = data.get_column();
|
||||
if (data_column->get_num_values() == 3 &&
|
||||
data_column->get_numeric_type() == NT_float32) {
|
||||
// Table of points is a table of LPoint3f's. Optimize this
|
||||
// common case.
|
||||
int data_index = new_format->get_array_with(new_format->get_point(ci));
|
||||
PT(GeomVertexArrayData) data_array = new_data->modify_array(data_index);
|
||||
PT(GeomVertexArrayDataHandle) data_handle = data_array->modify_handle();
|
||||
unsigned char *datat = data_handle->get_write_pointer();
|
||||
datat += data_column->get_start();
|
||||
size_t stride = data_array->get_array_format()->get_stride();
|
||||
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LPoint3f &vertex = *(LPoint3f *)(&datat[j * stride]);
|
||||
int bi = blendt[j];
|
||||
tb_table->get_blend(bi).transform_point(vertex, current_thread);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
nassertv(begin < end);
|
||||
|
||||
} else if (data_column->get_num_values() == 4) {
|
||||
// Use the GeomVertexRewriter to adjust the 4-component
|
||||
// points.
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LPoint4 vertex = data.get_data4();
|
||||
int bi = blendt[j];
|
||||
tb_table->get_blend(bi).transform_point(vertex, current_thread);
|
||||
data.set_data4(vertex);
|
||||
}
|
||||
}
|
||||
int first_vertex = begin;
|
||||
int first_bi = blendt[first_vertex];
|
||||
|
||||
} else {
|
||||
// Use the GeomVertexRewriter to adjust the 3-component
|
||||
// points.
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LPoint3 vertex = data.get_data3();
|
||||
int bi = blendt[j];
|
||||
tb_table->get_blend(bi).transform_point(vertex, current_thread);
|
||||
data.set_data3(vertex);
|
||||
while (first_vertex < end) {
|
||||
// At this point, first_vertex is the first of a series of
|
||||
// vertices that shares the blend index first_bi.
|
||||
|
||||
// Scan for the end of this series of vertices--we're
|
||||
// looking for the next vertex with a different blend index.
|
||||
int next_vertex = first_vertex;
|
||||
int next_bi = first_bi;
|
||||
++next_vertex;
|
||||
while (next_vertex < end) {
|
||||
next_bi = blendt[next_vertex];
|
||||
if (next_bi != first_bi) {
|
||||
break;
|
||||
}
|
||||
++next_vertex;
|
||||
}
|
||||
|
||||
// We've just reached the end of the vertices with a matching
|
||||
// blend index. Transform all those vertices as a block.
|
||||
LMatrix4 mat;
|
||||
tb_table->get_blend(first_bi).get_blend(mat, current_thread);
|
||||
new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
|
||||
|
||||
first_vertex = next_vertex;
|
||||
first_bi = next_bi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Also process vectors: normals, etc.
|
||||
for (ci = 0; ci < new_format->get_num_vectors(); ci++) {
|
||||
GeomVertexRewriter data(new_data, new_format->get_vector(ci));
|
||||
const GeomVertexColumn *data_column = data.get_column();
|
||||
if (data_column->get_num_values() == 3 &&
|
||||
data_column->get_numeric_type() == NT_float32) {
|
||||
// Table of vectors is a table of LVector3f's. Optimize this
|
||||
// common case.
|
||||
int data_index = new_format->get_array_with(new_format->get_vector(ci));
|
||||
PT(GeomVertexArrayData) data_array = new_data->modify_array(data_index);
|
||||
PT(GeomVertexArrayDataHandle) data_handle = data_array->modify_handle();
|
||||
unsigned char *datat = data_handle->get_write_pointer();
|
||||
datat += data_column->get_start();
|
||||
size_t stride = data_array->get_array_format()->get_stride();
|
||||
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LVector3f &vertex = *(LVector3f *)(&datat[j * stride]);
|
||||
int bi = blendt[j];
|
||||
tb_table->get_blend(bi).transform_vector(vertex, current_thread);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
nassertv(begin < end);
|
||||
|
||||
int first_vertex = begin;
|
||||
int first_bi = blendt[first_vertex];
|
||||
|
||||
} else {
|
||||
// Use the GeomVertexRewriter to adjust the vectors.
|
||||
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LVector3 vertex = data.get_data3();
|
||||
int bi = blendt[j];
|
||||
tb_table->get_blend(bi).transform_vector(vertex, current_thread);
|
||||
data.set_data3(vertex);
|
||||
while (first_vertex < end) {
|
||||
// At this point, first_vertex is the first of a series of
|
||||
// vertices that shares the blend index first_bi.
|
||||
|
||||
// Scan for the end of this series of vertices--we're
|
||||
// looking for the next vertex with a different blend index.
|
||||
int next_vertex = first_vertex;
|
||||
int next_bi = first_bi;
|
||||
++next_vertex;
|
||||
while (next_vertex < end) {
|
||||
next_bi = blendt[next_vertex];
|
||||
if (next_bi != first_bi) {
|
||||
break;
|
||||
}
|
||||
++next_vertex;
|
||||
}
|
||||
|
||||
// We've just reached the end of the vertices with a matching
|
||||
// blend index. Transform all those vertices as a block.
|
||||
LMatrix4 mat;
|
||||
tb_table->get_blend(first_bi).get_blend(mat, current_thread);
|
||||
new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
|
||||
|
||||
first_vertex = next_vertex;
|
||||
first_bi = next_bi;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1693,51 +1719,174 @@ update_animated_vertices(GeomVertexData::CData *cdata, Thread *current_thread) {
|
||||
int ci;
|
||||
for (ci = 0; ci < new_format->get_num_points(); ci++) {
|
||||
GeomVertexRewriter data(new_data, new_format->get_point(ci));
|
||||
const GeomVertexColumn *data_column = data.get_column();
|
||||
|
||||
if (data_column->get_num_values() == 4) {
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
blendi.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LPoint4 vertex = data.get_data4();
|
||||
int bi = blendi.get_data1i();
|
||||
tb_table->get_blend(bi).transform_point(vertex, current_thread);
|
||||
data.set_data4(vertex);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
blendi.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LPoint3 vertex = data.get_data3();
|
||||
int bi = blendi.get_data1i();
|
||||
tb_table->get_blend(bi).transform_point(vertex, current_thread);
|
||||
data.set_data3(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ci = 0; ci < new_format->get_num_vectors(); ci++) {
|
||||
GeomVertexRewriter data(new_data, new_format->get_vector(ci));
|
||||
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
data.set_row_unsafe(begin);
|
||||
nassertv(begin < end);
|
||||
blendi.set_row_unsafe(begin);
|
||||
for (int j = begin; j < end; ++j) {
|
||||
LVector3 vertex = data.get_data3();
|
||||
int bi = blendi.get_data1i();
|
||||
tb_table->get_blend(bi).transform_vector(vertex, current_thread);
|
||||
data.set_data3(vertex);
|
||||
|
||||
int first_vertex = begin;
|
||||
int first_bi = blendi.get_data1i();
|
||||
|
||||
while (first_vertex < end) {
|
||||
// At this point, first_vertex is the first of a series of
|
||||
// vertices that shares the blend index first_bi.
|
||||
|
||||
// Scan for the end of this series of vertices--we're
|
||||
// looking for the next vertex with a different blend index.
|
||||
int next_vertex = first_vertex;
|
||||
int next_bi = first_bi;
|
||||
++next_vertex;
|
||||
while (next_vertex < end) {
|
||||
next_bi = blendi.get_data1i();
|
||||
if (next_bi != first_bi) {
|
||||
break;
|
||||
}
|
||||
++next_vertex;
|
||||
}
|
||||
|
||||
// We've just reached the end of the vertices with a matching
|
||||
// blend index. Transform all those vertices as a block.
|
||||
LMatrix4 mat;
|
||||
tb_table->get_blend(first_bi).get_blend(mat, current_thread);
|
||||
new_data->do_transform_point_column(new_format, data, mat, first_vertex, next_vertex);
|
||||
|
||||
first_vertex = next_vertex;
|
||||
first_bi = next_bi;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (ci = 0; ci < new_format->get_num_vectors(); ci++) {
|
||||
GeomVertexRewriter data(new_data, new_format->get_vector(ci));
|
||||
|
||||
for (int i = 0; i < num_subranges; ++i) {
|
||||
int begin = rows.get_subrange_begin(i);
|
||||
int end = rows.get_subrange_end(i);
|
||||
nassertv(begin != end);
|
||||
blendi.set_row_unsafe(begin);
|
||||
|
||||
int first_vertex = begin;
|
||||
int first_bi = blendi.get_data1i();
|
||||
|
||||
while (first_vertex < end) {
|
||||
// At this point, first_vertex is the first of a series of
|
||||
// vertices that shares the blend index first_bi.
|
||||
|
||||
// Scan for the end of this series of vertices--we're
|
||||
// looking for the next vertex with a different blend index.
|
||||
int next_vertex = first_vertex;
|
||||
int next_bi = first_bi;
|
||||
++next_vertex;
|
||||
while (next_vertex < end) {
|
||||
next_bi = blendi.get_data1i();
|
||||
if (next_bi != first_bi) {
|
||||
break;
|
||||
}
|
||||
++next_vertex;
|
||||
}
|
||||
|
||||
// We've just reached the end of the vertices with a matching
|
||||
// blend index. Transform all those vertices as a block.
|
||||
LMatrix4 mat;
|
||||
tb_table->get_blend(first_bi).get_blend(mat, current_thread);
|
||||
new_data->do_transform_vector_column(new_format, data, mat, first_vertex, next_vertex);
|
||||
|
||||
first_vertex = next_vertex;
|
||||
first_bi = next_bi;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::do_transform_point_column
|
||||
// Access: Private
|
||||
// Description: Transforms a range of vertices for one particular
|
||||
// column, as a point.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomVertexData::
|
||||
do_transform_point_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
|
||||
const LMatrix4 &mat, int begin_row, int end_row) {
|
||||
const GeomVertexColumn *data_column = data.get_column();
|
||||
|
||||
if (data_column->get_num_values() == 3 &&
|
||||
data_column->get_numeric_type() == NT_float32) {
|
||||
// The table of points is a table of LPoint3f's. Optimize this
|
||||
// common case.
|
||||
PT(GeomVertexArrayDataHandle) data_handle = data.get_array_handle();
|
||||
PT(GeomVertexArrayData) data_array = data_handle->get_object();
|
||||
|
||||
unsigned char *datat = data_handle->get_write_pointer();
|
||||
datat += data_column->get_start();
|
||||
size_t stride = data_array->get_array_format()->get_stride();
|
||||
|
||||
LMatrix4f matf = LCAST(float, mat);
|
||||
for (int j = begin_row; j < end_row; ++j) {
|
||||
LPoint3f &vertex = *(LPoint3f *)(&datat[j * stride]);
|
||||
vertex = vertex * matf;
|
||||
}
|
||||
|
||||
} else if (data_column->get_num_values() == 4) {
|
||||
// Use the GeomVertexRewriter to adjust the 4-component
|
||||
// points.
|
||||
|
||||
data.set_row_unsafe(begin_row);
|
||||
for (int j = begin_row; j < end_row; ++j) {
|
||||
LPoint4 vertex = data.get_data4();
|
||||
data.set_data4(vertex * mat);
|
||||
}
|
||||
|
||||
} else {
|
||||
// Use the GeomVertexRewriter to adjust the 3-component
|
||||
// points.
|
||||
|
||||
data.set_row_unsafe(begin_row);
|
||||
for (int j = begin_row; j < end_row; ++j) {
|
||||
LPoint3 vertex = data.get_data3();
|
||||
data.set_data3(vertex * mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexData::do_transform_vector_column
|
||||
// Access: Private
|
||||
// Description: Transforms a range of vertices for one particular
|
||||
// column, as a vector.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomVertexData::
|
||||
do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
|
||||
const LMatrix4 &mat, int begin_row, int end_row) {
|
||||
const GeomVertexColumn *data_column = data.get_column();
|
||||
|
||||
if (data_column->get_num_values() == 3 &&
|
||||
data_column->get_numeric_type() == NT_float32) {
|
||||
// The table of vectors is a table of LVector3f's. Optimize this
|
||||
// common case.
|
||||
PT(GeomVertexArrayDataHandle) data_handle = data.get_array_handle();
|
||||
PT(GeomVertexArrayData) data_array = data_handle->get_object();
|
||||
|
||||
unsigned char *datat = data_handle->get_write_pointer();
|
||||
datat += data_column->get_start();
|
||||
size_t stride = data_array->get_array_format()->get_stride();
|
||||
|
||||
LMatrix4f matf = LCAST(float, mat);
|
||||
for (int j = begin_row; j < end_row; ++j) {
|
||||
LVector3f &vector = *(LVector3f *)(&datat[j * stride]);
|
||||
vector = vector * matf;
|
||||
}
|
||||
|
||||
} else {
|
||||
// Use the GeomVertexRewriter to transform the vectors.
|
||||
|
||||
data.set_row_unsafe(begin_row);
|
||||
for (int j = begin_row; j < end_row; ++j) {
|
||||
LVector3 vertex = data.get_data3();
|
||||
data.set_data3(vertex * mat);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
class FactoryParams;
|
||||
class GeomVertexColumn;
|
||||
class GeomVertexRewriter;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : GeomVertexData
|
||||
@ -152,6 +153,8 @@ PUBLISHED:
|
||||
|
||||
CPT(GeomVertexData) animate_vertices(bool force, Thread *current_thread) const;
|
||||
void clear_animated_vertices();
|
||||
void transform_vertices(const LMatrix4 &mat);
|
||||
void transform_vertices(const LMatrix4 &mat, int begin_row, int end_row);
|
||||
|
||||
PT(GeomVertexData)
|
||||
replace_column(InternalName *name, int num_components,
|
||||
@ -315,6 +318,10 @@ private:
|
||||
|
||||
private:
|
||||
void update_animated_vertices(CData *cdata, Thread *current_thread);
|
||||
void do_transform_point_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
|
||||
const LMatrix4 &mat, int begin_row, int end_row);
|
||||
void do_transform_vector_column(const GeomVertexFormat *format, GeomVertexRewriter &data,
|
||||
const LMatrix4 &mat, int begin_row, int end_row);
|
||||
|
||||
static PStatCollector _convert_pcollector;
|
||||
static PStatCollector _scale_color_pcollector;
|
||||
|
@ -206,6 +206,18 @@ get_array_data() const {
|
||||
return _array_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexReader::get_array_handle
|
||||
// Access: Published
|
||||
// Description: Returns the read handle to the array object that the
|
||||
// read is currently processing. This low-level call
|
||||
// should be used with caution.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const GeomVertexArrayDataHandle *GeomVertexReader::
|
||||
get_array_handle() const {
|
||||
return _handle;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexReader::get_current_thread
|
||||
// Access: Published
|
||||
|
@ -82,6 +82,7 @@ PUBLISHED:
|
||||
|
||||
INLINE const GeomVertexData *get_vertex_data() const;
|
||||
INLINE const GeomVertexArrayData *get_array_data() const;
|
||||
INLINE const GeomVertexArrayDataHandle *get_array_handle() const;
|
||||
INLINE Thread *get_current_thread() const;
|
||||
|
||||
INLINE void set_force(bool force);
|
||||
|
@ -159,6 +159,20 @@ get_array_data() const {
|
||||
return GeomVertexWriter::get_array_data();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexRewriter::get_array_handle
|
||||
// Access: Published
|
||||
// Description: Returns the write handle to the array object that the
|
||||
// rewriter is currently processing. This low-level call
|
||||
// should be used with caution; be careful with
|
||||
// modifying the data in the handle out from under the
|
||||
// GeomVertexRewriter.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE GeomVertexArrayDataHandle *GeomVertexRewriter::
|
||||
get_array_handle() const {
|
||||
return GeomVertexWriter::get_array_handle();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexRewriter::set_column
|
||||
// Access: Published
|
||||
|
@ -53,6 +53,7 @@ PUBLISHED:
|
||||
|
||||
INLINE GeomVertexData *get_vertex_data() const;
|
||||
INLINE GeomVertexArrayData *get_array_data() const;
|
||||
INLINE GeomVertexArrayDataHandle *get_array_handle() const;
|
||||
|
||||
INLINE bool set_column(int column);
|
||||
INLINE bool set_column(const string &name);
|
||||
|
@ -201,6 +201,20 @@ get_array_data() const {
|
||||
return _array_data;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexWriter::get_array_handle
|
||||
// Access: Published
|
||||
// Description: Returns the write handle to the array object that the
|
||||
// writer is currently processing. This low-level call
|
||||
// should be used with caution; be careful with
|
||||
// modifying the data in the handle out from under the
|
||||
// GeomVertexWriter.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE GeomVertexArrayDataHandle *GeomVertexWriter::
|
||||
get_array_handle() const {
|
||||
return _handle;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomVertexWriter::get_current_thread
|
||||
// Access: Published
|
||||
|
@ -94,6 +94,7 @@ PUBLISHED:
|
||||
|
||||
INLINE GeomVertexData *get_vertex_data() const;
|
||||
INLINE GeomVertexArrayData *get_array_data() const;
|
||||
INLINE GeomVertexArrayDataHandle *get_array_handle() const;
|
||||
INLINE Thread *get_current_thread() const;
|
||||
|
||||
INLINE bool set_column(int column);
|
||||
|
@ -79,7 +79,7 @@ add_transform(const VertexTransform *transform, PN_stdfloat weight) {
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformBlend::remove_transform
|
||||
// Access: Published
|
||||
// Description: Removes the indicated transform to the blend.
|
||||
// Description: Removes the indicated transform from the blend.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformBlend::
|
||||
remove_transform(const VertexTransform *transform) {
|
||||
@ -94,6 +94,38 @@ remove_transform(const VertexTransform *transform) {
|
||||
clear_result(current_thread);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformBlend::limit_transforms
|
||||
// Access: Published
|
||||
// Description: If the total number of transforms in the blend
|
||||
// exceeds max_transforms, removes the n least-important
|
||||
// transforms as needed to reduce the number of
|
||||
// transforms to max_transforms.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TransformBlend::
|
||||
limit_transforms(int max_transforms) {
|
||||
if (max_transforms <= 0) {
|
||||
_entries.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
while (_entries.size() > max_transforms) {
|
||||
// Repeatedly find and remove the least-important transform.
|
||||
nassertv(!_entries.empty());
|
||||
Entries::iterator ei_least = _entries.begin();
|
||||
Entries::iterator ei = ei_least;
|
||||
++ei;
|
||||
while (ei != _entries.end()) {
|
||||
if ((*ei)._weight < (*ei_least)._weight) {
|
||||
ei_least = ei;
|
||||
}
|
||||
++ei;
|
||||
}
|
||||
|
||||
_entries.erase(ei_least);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TransformBlend::normalize_weights
|
||||
// Access: Published
|
||||
|
@ -57,6 +57,7 @@ PUBLISHED:
|
||||
|
||||
void add_transform(const VertexTransform *transform, PN_stdfloat weight);
|
||||
void remove_transform(const VertexTransform *transform);
|
||||
void limit_transforms(int max_transforms);
|
||||
void normalize_weights();
|
||||
bool has_transform(const VertexTransform *transform) const;
|
||||
PN_stdfloat get_weight(const VertexTransform *transform) const;
|
||||
|
Loading…
x
Reference in New Issue
Block a user