beginning morph animations
This commit is contained in:
parent
bc56b6467b
commit
19ef896a9b
|
|
@ -50,9 +50,10 @@ munge_format_impl(const qpGeomVertexFormat *orig) {
|
|||
const qpGeomVertexDataType *color_type =
|
||||
format->get_data_type(InternalName::get_color());
|
||||
if (color_type != (qpGeomVertexDataType *)NULL &&
|
||||
color_type->get_numeric_type() == qpGeomVertexDataType::NT_packed_8888) {
|
||||
(color_type->get_numeric_type() == qpGeomVertexDataType::NT_packed_8888 ||
|
||||
color_type->get_contents() != qpGeomVertexDataType::NT_rgba)) {
|
||||
// We need to convert the color format; OpenGL doesn't support the
|
||||
// byte order of DirectX's packed_argb format.
|
||||
// byte order of DirectX's packed ARGB format.
|
||||
int color_array = format->get_array_with(InternalName::get_color());
|
||||
|
||||
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*format);
|
||||
|
|
|
|||
|
|
@ -2676,7 +2676,7 @@ prepare_index_buffer(qpGeomPrimitive *data) {
|
|||
|
||||
if (GLCAT.is_debug()) {
|
||||
GLCAT.debug()
|
||||
<< "creating vertex buffer " << gibc->_index << "\n";
|
||||
<< "creating index buffer " << gibc->_index << "\n";
|
||||
}
|
||||
|
||||
report_my_gl_errors();
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
preparedGraphicsObjects.I preparedGraphicsObjects.h \
|
||||
lens.h lens.I \
|
||||
savedContext.I savedContext.h \
|
||||
sliderTable.I sliderTable.h \
|
||||
texture.I texture.h \
|
||||
textureContext.I textureContext.h \
|
||||
texturePool.I texturePool.h \
|
||||
|
|
@ -54,8 +55,10 @@
|
|||
transformBlend.I transformBlend.h \
|
||||
transformBlendPalette.I transformBlendPalette.h \
|
||||
transformPalette.I transformPalette.h \
|
||||
userVertexSlider.I userVertexSlider.h \
|
||||
userVertexTransform.I userVertexTransform.h \
|
||||
vertexBufferContext.I vertexBufferContext.h \
|
||||
vertexSlider.I vertexSlider.h \
|
||||
vertexTransform.I vertexTransform.h
|
||||
|
||||
#define INCLUDED_SOURCES \
|
||||
|
|
@ -92,13 +95,17 @@
|
|||
perspectiveLens.cxx \
|
||||
preparedGraphicsObjects.cxx \
|
||||
lens.cxx \
|
||||
savedContext.cxx texture.cxx textureContext.cxx texturePool.cxx \
|
||||
savedContext.cxx \
|
||||
sliderTable.cxx \
|
||||
texture.cxx textureContext.cxx texturePool.cxx \
|
||||
textureStage.cxx \
|
||||
transformBlend.cxx \
|
||||
transformBlendPalette.cxx \
|
||||
transformPalette.cxx \
|
||||
userVertexSlider.cxx \
|
||||
userVertexTransform.cxx \
|
||||
vertexBufferContext.cxx \
|
||||
vertexSlider.cxx \
|
||||
vertexTransform.cxx
|
||||
|
||||
#define INSTALL_HEADERS \
|
||||
|
|
@ -139,6 +146,7 @@
|
|||
preparedGraphicsObjects.I preparedGraphicsObjects.h \
|
||||
lens.h lens.I \
|
||||
savedContext.I savedContext.h \
|
||||
sliderTable.I sliderTable.h \
|
||||
texture.I texture.h \
|
||||
textureContext.I textureContext.h \
|
||||
texturePool.I texturePool.h \
|
||||
|
|
@ -146,8 +154,10 @@
|
|||
transformBlend.I transformBlend.h \
|
||||
transformBlendPalette.I transformBlendPalette.h \
|
||||
transformPalette.I transformPalette.h \
|
||||
userVertexSlider.I userVertexSlider.h \
|
||||
userVertexTransform.I userVertexTransform.h \
|
||||
vertexBufferContext.I vertexBufferContext.h \
|
||||
vertexSlider.I vertexSlider.h \
|
||||
vertexTransform.I vertexTransform.h
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -40,13 +40,16 @@
|
|||
#include "matrixLens.h"
|
||||
#include "perspectiveLens.h"
|
||||
#include "lens.h"
|
||||
#include "sliderTable.h"
|
||||
#include "texture.h"
|
||||
#include "textureStage.h"
|
||||
#include "textureContext.h"
|
||||
#include "transformBlendPalette.h"
|
||||
#include "transformPalette.h"
|
||||
#include "userVertexSlider.h"
|
||||
#include "userVertexTransform.h"
|
||||
#include "vertexTransform.h"
|
||||
#include "vertexSlider.h"
|
||||
#include "geomContext.h"
|
||||
#include "vertexBufferContext.h"
|
||||
#include "indexBufferContext.h"
|
||||
|
|
@ -212,13 +215,16 @@ ConfigureFn(config_gobj) {
|
|||
MatrixLens::init_type();
|
||||
PerspectiveLens::init_type();
|
||||
Lens::init_type();
|
||||
SliderTable::init_type();
|
||||
Texture::init_type();
|
||||
dDrawable::init_type();
|
||||
TextureStage::init_type();
|
||||
TransformBlendPalette::init_type();
|
||||
TransformPalette::init_type();
|
||||
UserVertexSlider::init_type();
|
||||
UserVertexTransform::init_type();
|
||||
VertexTransform::init_type();
|
||||
VertexSlider::init_type();
|
||||
InternalName::init_type();
|
||||
|
||||
//Registration of writeable object's creation
|
||||
|
|
@ -248,10 +254,12 @@ ConfigureFn(config_gobj) {
|
|||
OrthographicLens::register_with_read_factory();
|
||||
MatrixLens::register_with_read_factory();
|
||||
PerspectiveLens::register_with_read_factory();
|
||||
SliderTable::register_with_read_factory();
|
||||
Texture::register_with_read_factory();
|
||||
TextureStage::register_with_read_factory();
|
||||
TransformBlendPalette::register_with_read_factory();
|
||||
TransformPalette::register_with_read_factory();
|
||||
UserVertexSlider::register_with_read_factory();
|
||||
UserVertexTransform::register_with_read_factory();
|
||||
InternalName::register_with_read_factory();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include "perspectiveLens.cxx"
|
||||
#include "preparedGraphicsObjects.cxx"
|
||||
#include "savedContext.cxx"
|
||||
#include "sliderTable.cxx"
|
||||
#include "texture.cxx"
|
||||
#include "textureContext.cxx"
|
||||
#include "texturePool.cxx"
|
||||
|
|
@ -19,6 +20,8 @@
|
|||
#include "transformBlend.cxx"
|
||||
#include "transformBlendPalette.cxx"
|
||||
#include "transformPalette.cxx"
|
||||
#include "userVertexSlider.cxx"
|
||||
#include "userVertexTransform.cxx"
|
||||
#include "vertexBufferContext.cxx"
|
||||
#include "vertexSlider.cxx"
|
||||
#include "vertexTransform.cxx"
|
||||
|
|
|
|||
|
|
@ -111,6 +111,74 @@ get_name() const {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: InternalName::find_ancestor
|
||||
// Access: Published
|
||||
// Description: Returns the index of the ancestor with the indicated
|
||||
// basename, or -1 if no ancestor has that basename.
|
||||
// Returns 0 if this name has the basename.
|
||||
//
|
||||
// This index value may be passed to get_ancestor() or
|
||||
// get_net_basename() to retrieve more information about
|
||||
// the indicated name.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int InternalName::
|
||||
find_ancestor(const string &basename) const {
|
||||
if (_basename == basename) {
|
||||
return 0;
|
||||
|
||||
} else if (_parent != (InternalName *)NULL) {
|
||||
int index = _parent->find_ancestor(basename);
|
||||
if (index >= 0) {
|
||||
return index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: InternalName::get_ancestor
|
||||
// Access: Published
|
||||
// Description: Returns the ancestor with the indicated index number.
|
||||
// 0 is this name itself, 1 is the name's parent, 2 is
|
||||
// the parent's parent, and so on. If there are not
|
||||
// enough ancestors, returns the root InternalName.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
const InternalName *InternalName::
|
||||
get_ancestor(int n) const {
|
||||
if (n == 0) {
|
||||
return this;
|
||||
|
||||
} else if (_parent != (InternalName *)NULL) {
|
||||
return _parent->get_ancestor(n - 1);
|
||||
|
||||
} else {
|
||||
return get_root();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: InternalName::get_net_basename
|
||||
// Access: Published
|
||||
// Description: Returns the basename of this name prefixed by the
|
||||
// indicated number of ancestors. 0 is this name's
|
||||
// basename, 1 is parent.basename, 2 is
|
||||
// grandparent.parent.basename, and so on.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string InternalName::
|
||||
get_net_basename(int n) const {
|
||||
if (n == 0) {
|
||||
return _basename;
|
||||
|
||||
} else if (_parent != (InternalName *)NULL && _parent != get_root()) {
|
||||
return _parent->get_net_basename(n - 1) + "." + _basename;
|
||||
|
||||
} else {
|
||||
return _basename;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: InternalName::output
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -55,6 +55,10 @@ PUBLISHED:
|
|||
string get_name() const;
|
||||
INLINE const string &get_basename() const;
|
||||
|
||||
int find_ancestor(const string &basename) const;
|
||||
const InternalName *get_ancestor(int n) const;
|
||||
string get_net_basename(int n) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
|
||||
// Some predefined built-in names.
|
||||
|
|
|
|||
|
|
@ -150,6 +150,35 @@ clear_transform_blend_palette() {
|
|||
set_transform_blend_palette(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_slider_table
|
||||
// Access: Published
|
||||
// Description: Returns a const pointer to the SliderTable
|
||||
// assigned to this data. Vertices within the vertex
|
||||
// data will look up their morph offsets, if any, within
|
||||
// this table.
|
||||
//
|
||||
// This will return NULL if the vertex data does not
|
||||
// have a SliderTable assigned.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const SliderTable *qpGeomVertexData::
|
||||
get_slider_table() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_slider_table;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::clear_slider_table
|
||||
// Access: Published
|
||||
// Description: Sets the SliderTable pointer to NULL,
|
||||
// removing the table from the vertex data. This
|
||||
// disables morph (blend shape) animation.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void qpGeomVertexData::
|
||||
clear_slider_table() {
|
||||
set_slider_table(NULL);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_modified
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "qpgeomVertexData.h"
|
||||
#include "qpgeomVertexReader.h"
|
||||
#include "qpgeomVertexWriter.h"
|
||||
#include "qpgeomVertexRewriter.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
|
@ -241,6 +242,51 @@ set_transform_blend_palette(const TransformBlendPalette *palette) {
|
|||
cdata->_animated_vertices_modified = UpdateSeq();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::modify_slider_table
|
||||
// Access: Published
|
||||
// Description: Returns a modifiable pointer to the current
|
||||
// SliderTable on this vertex data, if any, or
|
||||
// NULL if there is not a SliderTable. See
|
||||
// get_slider_table().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SliderTable *qpGeomVertexData::
|
||||
modify_slider_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->_slider_table->get_ref_count() > 1) {
|
||||
cdata->_slider_table = new SliderTable(*cdata->_slider_table);
|
||||
}
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
cdata->_animated_vertices_modified = UpdateSeq();
|
||||
|
||||
return cdata->_slider_table;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::set_slider_table
|
||||
// Access: Published
|
||||
// Description: Replaces the SliderTable on this vertex
|
||||
// data with the indicated table. There should be an
|
||||
// entry in this table for each kind of morph offset
|
||||
// defined in the vertex data.
|
||||
//
|
||||
// The SliderTable object must have been registered
|
||||
// prior to setting it on the GeomVertexData.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
set_slider_table(const SliderTable *table) {
|
||||
nassertv(table == (SliderTable *)NULL || table->is_registered());
|
||||
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_slider_table = (SliderTable *)table;
|
||||
cdata->_modified = qpGeom::get_next_modified();
|
||||
cdata->_animated_vertices_modified = UpdateSeq();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_num_bytes
|
||||
// Access: Published
|
||||
|
|
@ -261,13 +307,149 @@ get_num_bytes() const {
|
|||
return num_bytes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::copy_from
|
||||
// Access: Published
|
||||
// Description: Copies all the data from the other array into the
|
||||
// corresponding data types in this array, by matching
|
||||
// data types name-by-name.
|
||||
//
|
||||
// keep_data_objects specifies what to do when one or
|
||||
// more of the arrays can be copied without the need to
|
||||
// apply any conversion operation. If it is true, the
|
||||
// original GeomVertexArrayData objects in this object
|
||||
// are retained, but their data arrays are copied
|
||||
// pointerwise from the source; if it is false, then the
|
||||
// GeomVertexArrayData objects themselves are copied
|
||||
// pointerwise from the source.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
copy_from(const qpGeomVertexData &source, bool keep_data_objects) {
|
||||
const qpGeomVertexFormat *source_format = source.get_format();
|
||||
const qpGeomVertexFormat *dest_format = get_format();
|
||||
|
||||
int num_vertices = source.get_num_vertices();
|
||||
int num_arrays = source_format->get_num_arrays();
|
||||
int source_i;
|
||||
|
||||
// First, check to see if any arrays can be simply appropriated for
|
||||
// the new format, without changing the data.
|
||||
pset<int> done_arrays;
|
||||
|
||||
for (source_i = 0; source_i < num_arrays; ++source_i) {
|
||||
const qpGeomVertexArrayFormat *source_array_format =
|
||||
source_format->get_array(source_i);
|
||||
|
||||
bool array_done = false;
|
||||
|
||||
int dest_num_arrays = dest_format->get_num_arrays();
|
||||
for (int dest_i = 0;
|
||||
dest_i < dest_num_arrays && !array_done;
|
||||
++dest_i) {
|
||||
const qpGeomVertexArrayFormat *dest_array_format =
|
||||
dest_format->get_array(dest_i);
|
||||
if (dest_array_format->is_data_subset_of(*source_array_format)) {
|
||||
// Great! Just use the same data for this one.
|
||||
if (keep_data_objects) {
|
||||
// Copy the data, but keep the same GeomVertexArrayData object.
|
||||
|
||||
// Maybe it even has the same data pointer already. If so,
|
||||
// avoid flipping the modified flag.
|
||||
CPTA_uchar source_data = source.get_array(source_i)->get_data();
|
||||
if (get_array(dest_i)->get_data() != source_data) {
|
||||
modify_array(dest_i)->set_data(source_data);
|
||||
}
|
||||
} else {
|
||||
// Copy the GeomVertexArrayData object.
|
||||
if (get_array(dest_i) != source.get_array(source_i)) {
|
||||
set_array(dest_i, source.get_array(source_i));
|
||||
}
|
||||
}
|
||||
|
||||
array_done = true;
|
||||
done_arrays.insert(dest_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure the arrays we didn't share are all filled in.
|
||||
set_num_vertices(num_vertices);
|
||||
|
||||
// Now go back through and copy any data that's left over.
|
||||
for (source_i = 0; source_i < num_arrays; ++source_i) {
|
||||
CPTA_uchar array_data = source.get_array(source_i)->get_data();
|
||||
const qpGeomVertexArrayFormat *source_array_format = source_format->get_array(source_i);
|
||||
int num_data_types = source_array_format->get_num_data_types();
|
||||
for (int di = 0; di < num_data_types; ++di) {
|
||||
const qpGeomVertexDataType *source_data_type = source_array_format->get_data_type(di);
|
||||
|
||||
int dest_i = dest_format->get_array_with(source_data_type->get_name());
|
||||
if (dest_i >= 0 && done_arrays.count(dest_i) == 0) {
|
||||
// The data type exists in the new format; we have to copy it.
|
||||
const qpGeomVertexArrayFormat *dest_array_format =
|
||||
dest_format->get_array(dest_i);
|
||||
const qpGeomVertexDataType *dest_data_type =
|
||||
dest_array_format->get_data_type(source_data_type->get_name());
|
||||
|
||||
if (dest_data_type->is_bytewise_equivalent(*source_data_type)) {
|
||||
// We can do a quick bytewise copy.
|
||||
PTA_uchar dest_array_data = modify_array(dest_i)->modify_data();
|
||||
|
||||
bytewise_copy(dest_array_data + dest_data_type->get_start(),
|
||||
dest_array_format->get_stride(),
|
||||
array_data + source_data_type->get_start(), source_array_format->get_stride(),
|
||||
source_data_type, num_vertices);
|
||||
|
||||
} else if (dest_data_type->is_packed_argb() &&
|
||||
source_data_type->is_uint8_rgba()) {
|
||||
// A common special case: OpenGL color to DirectX color.
|
||||
PTA_uchar dest_array_data = modify_array(dest_i)->modify_data();
|
||||
|
||||
uint8_rgba_to_packed_argb
|
||||
(dest_array_data + dest_data_type->get_start(),
|
||||
dest_array_format->get_stride(),
|
||||
array_data + source_data_type->get_start(), source_array_format->get_stride(),
|
||||
num_vertices);
|
||||
|
||||
} else if (dest_data_type->is_uint8_rgba() &&
|
||||
source_data_type->is_packed_argb()) {
|
||||
// Another common special case: DirectX color to OpenGL
|
||||
// color.
|
||||
PTA_uchar dest_array_data = modify_array(dest_i)->modify_data();
|
||||
|
||||
packed_argb_to_uint8_rgba
|
||||
(dest_array_data + dest_data_type->get_start(),
|
||||
dest_array_format->get_stride(),
|
||||
array_data + source_data_type->get_start(), source_array_format->get_stride(),
|
||||
num_vertices);
|
||||
|
||||
} else {
|
||||
// A generic copy.
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "generic copy " << *dest_data_type << " from "
|
||||
<< *source_data_type << "\n";
|
||||
}
|
||||
qpGeomVertexWriter to(this);
|
||||
to.set_data_type(dest_i, dest_data_type);
|
||||
qpGeomVertexReader from(&source);
|
||||
from.set_data_type(source_i, source_data_type);
|
||||
|
||||
while (!from.is_at_end()) {
|
||||
to.set_data4f(from.get_data4f());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::convert_to
|
||||
// Access: Published
|
||||
// Description: Matches up the data types of this format with the
|
||||
// data types of the other format by name, and copies
|
||||
// the data vertex-by-vertex to a new set of data arrays
|
||||
// in the new format.
|
||||
// Description: Returns a new GeomVertexData that represents the same
|
||||
// contents as this one, with all data types matched up
|
||||
// name-by-name to the indicated new format.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomVertexData) qpGeomVertexData::
|
||||
convert_to(const qpGeomVertexFormat *new_format) const {
|
||||
|
|
@ -277,121 +459,18 @@ convert_to(const qpGeomVertexFormat *new_format) const {
|
|||
}
|
||||
|
||||
// Okay, convert the data to the new format.
|
||||
int num_vertices = get_num_vertices();
|
||||
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "Converting " << num_vertices << " vertices.\n";
|
||||
<< "Converting " << get_num_vertices() << " vertices.\n";
|
||||
}
|
||||
PStatTimer timer(_convert_pcollector);
|
||||
|
||||
PT(qpGeomVertexData) new_data =
|
||||
new qpGeomVertexData(get_name(), new_format, get_usage_hint());
|
||||
new_data->set_transform_blend_palette(get_transform_blend_palette());
|
||||
new_data->set_slider_table(get_slider_table());
|
||||
|
||||
pset<int> done_arrays;
|
||||
|
||||
int num_arrays = _format->get_num_arrays();
|
||||
int i;
|
||||
|
||||
// First, check to see if any arrays can be simply appropriated for
|
||||
// the new format, without changing the data.
|
||||
for (i = 0; i < num_arrays; ++i) {
|
||||
const qpGeomVertexArrayFormat *array_format =
|
||||
_format->get_array(i);
|
||||
|
||||
bool array_done = false;
|
||||
|
||||
int new_num_arrays = new_format->get_num_arrays();
|
||||
for (int new_i = 0;
|
||||
new_i < new_num_arrays && !array_done;
|
||||
++new_i) {
|
||||
const qpGeomVertexArrayFormat *new_array_format =
|
||||
new_format->get_array(new_i);
|
||||
if (new_array_format->is_data_subset_of(*array_format)) {
|
||||
// Great! Just use the same data for this one.
|
||||
new_data->set_array(new_i, get_array(i));
|
||||
array_done = true;
|
||||
|
||||
done_arrays.insert(new_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now make sure the arrays we didn't share are all filled in.
|
||||
new_data->set_num_vertices(num_vertices);
|
||||
|
||||
// Now go back through and copy any data that's left over.
|
||||
for (i = 0; i < num_arrays; ++i) {
|
||||
CPTA_uchar array_data = get_array(i)->get_data();
|
||||
const qpGeomVertexArrayFormat *array_format = _format->get_array(i);
|
||||
int num_data_types = array_format->get_num_data_types();
|
||||
for (int di = 0; di < num_data_types; ++di) {
|
||||
const qpGeomVertexDataType *data_type = array_format->get_data_type(di);
|
||||
|
||||
int new_i = new_format->get_array_with(data_type->get_name());
|
||||
if (new_i >= 0 && done_arrays.count(new_i) == 0) {
|
||||
// The data type exists in the new format; we have to copy it.
|
||||
const qpGeomVertexArrayFormat *new_array_format =
|
||||
new_format->get_array(new_i);
|
||||
const qpGeomVertexDataType *new_data_type =
|
||||
new_array_format->get_data_type(data_type->get_name());
|
||||
|
||||
if (new_data_type->is_bytewise_equivalent(*data_type)) {
|
||||
// We can do a quick bytewise copy.
|
||||
PTA_uchar new_array_data =
|
||||
new_data->modify_array(new_i)->modify_data();
|
||||
|
||||
bytewise_copy(new_array_data + new_data_type->get_start(),
|
||||
new_array_format->get_stride(),
|
||||
array_data + data_type->get_start(), array_format->get_stride(),
|
||||
data_type, num_vertices);
|
||||
|
||||
} else if (new_data_type->is_packed_argb() &&
|
||||
data_type->is_uint8_rgba()) {
|
||||
// A common special case: OpenGL color to DirectX color.
|
||||
PTA_uchar new_array_data =
|
||||
new_data->modify_array(new_i)->modify_data();
|
||||
|
||||
uint8_rgba_to_packed_argb
|
||||
(new_array_data + new_data_type->get_start(),
|
||||
new_array_format->get_stride(),
|
||||
array_data + data_type->get_start(), array_format->get_stride(),
|
||||
num_vertices);
|
||||
|
||||
} else if (new_data_type->is_uint8_rgba() &&
|
||||
data_type->is_packed_argb()) {
|
||||
// Another common special case: DirectX color to OpenGL
|
||||
// color.
|
||||
PTA_uchar new_array_data =
|
||||
new_data->modify_array(new_i)->modify_data();
|
||||
|
||||
packed_argb_to_uint8_rgba
|
||||
(new_array_data + new_data_type->get_start(),
|
||||
new_array_format->get_stride(),
|
||||
array_data + data_type->get_start(), array_format->get_stride(),
|
||||
num_vertices);
|
||||
|
||||
} else {
|
||||
// A generic copy.
|
||||
if (gobj_cat.is_debug()) {
|
||||
gobj_cat.debug()
|
||||
<< "generic copy " << *new_data_type << " from "
|
||||
<< *data_type << "\n";
|
||||
}
|
||||
qpGeomVertexWriter to(new_data);
|
||||
to.set_data_type(new_i, new_data_type);
|
||||
qpGeomVertexReader from(this);
|
||||
from.set_data_type(i, data_type);
|
||||
|
||||
while (!from.is_at_end()) {
|
||||
to.set_data4f(from.get_data4f());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_data->copy_from(*this, false);
|
||||
return new_data;
|
||||
}
|
||||
|
||||
|
|
@ -542,6 +621,7 @@ replace_data_type(const InternalName *name, int num_components,
|
|||
new qpGeomVertexData(get_name(), format, usage_hint);
|
||||
if (keep_animation) {
|
||||
new_data->set_transform_blend_palette(get_transform_blend_palette());
|
||||
new_data->set_slider_table(get_slider_table());
|
||||
}
|
||||
|
||||
int j = 0;
|
||||
|
|
@ -644,27 +724,35 @@ get_array_info(const InternalName *name,
|
|||
CPT(qpGeomVertexData) qpGeomVertexData::
|
||||
do_animate_vertices(bool from_app) const {
|
||||
CDReader cdata(_cycler);
|
||||
if (cdata->_transform_blend_palette == (TransformBlendPalette *)NULL) {
|
||||
// No vertex animation.
|
||||
|
||||
UpdateSeq modified;
|
||||
if (cdata->_transform_blend_palette != (TransformBlendPalette *)NULL) {
|
||||
if (cdata->_slider_table != (SliderTable *)NULL) {
|
||||
modified =
|
||||
max(cdata->_transform_blend_palette->get_modified(),
|
||||
cdata->_slider_table->get_modified());
|
||||
} else {
|
||||
modified = cdata->_transform_blend_palette->get_modified();
|
||||
}
|
||||
|
||||
} else if (cdata->_slider_table != (SliderTable *)NULL) {
|
||||
modified = cdata->_slider_table->get_modified();
|
||||
|
||||
} else {
|
||||
// No transform blend palette or slider table--ergo, no vertex
|
||||
// animation.
|
||||
return this;
|
||||
}
|
||||
|
||||
if (cdata->_animated_vertices == (qpGeomVertexData *)NULL) {
|
||||
CDWriter cdataw(((qpGeomVertexData *)this)->_cycler, cdata);
|
||||
((qpGeomVertexData *)this)->make_animated_vertices(cdataw);
|
||||
((qpGeomVertexData *)this)->update_animated_vertices(cdataw, from_app);
|
||||
return cdataw->_animated_vertices;
|
||||
} else {
|
||||
UpdateSeq blend_modified = cdata->_transform_blend_palette->get_modified();
|
||||
if (cdata->_animated_vertices_modified == blend_modified) {
|
||||
// No changes.
|
||||
return cdata->_animated_vertices;
|
||||
}
|
||||
CDWriter cdataw(((qpGeomVertexData *)this)->_cycler, cdata);
|
||||
cdataw->_animated_vertices_modified = blend_modified;
|
||||
((qpGeomVertexData *)this)->update_animated_vertices(cdataw, from_app);
|
||||
return cdataw->_animated_vertices;
|
||||
if (cdata->_animated_vertices_modified == modified &&
|
||||
cdata->_animated_vertices != (qpGeomVertexData *)NULL) {
|
||||
// No changes.
|
||||
return cdata->_animated_vertices;
|
||||
}
|
||||
CDWriter cdataw(((qpGeomVertexData *)this)->_cycler, cdata);
|
||||
cdataw->_animated_vertices_modified = modified;
|
||||
((qpGeomVertexData *)this)->update_animated_vertices(cdataw, from_app);
|
||||
return cdataw->_animated_vertices;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -787,22 +875,6 @@ do_set_num_vertices(int n, qpGeomVertexData::CDWriter &cdata) {
|
|||
return any_changed;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::make_animated_vertices
|
||||
// Access: Private
|
||||
// Description: Creates the GeomVertexData that represents the
|
||||
// results of computing the vertex animation on the CPU.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void qpGeomVertexData::
|
||||
make_animated_vertices(qpGeomVertexData::CDWriter &cdata) {
|
||||
// First, make a new format that doesn't have the transform_blend
|
||||
// array.
|
||||
cdata->_animated_vertices = replace_data_type
|
||||
(InternalName::get_transform_blend(), 0, qpGeomVertexDataType::NT_uint16,
|
||||
qpGeomVertexDataType::C_index,
|
||||
min(get_usage_hint(), qpGeomUsageHint::UH_dynamic), false);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::update_animated_vertices
|
||||
// Access: Private
|
||||
|
|
@ -825,46 +897,133 @@ update_animated_vertices(qpGeomVertexData::CDWriter &cdata, bool from_app) {
|
|||
PStatTimer timer(collector);
|
||||
#endif
|
||||
|
||||
CPT(TransformBlendPalette) palette = cdata->_transform_blend_palette;
|
||||
nassertv(palette != (TransformBlendPalette *)NULL);
|
||||
|
||||
// Recompute all the blends up front, so we don't have to test each
|
||||
// one for staleness at each vertex.
|
||||
int num_blends = palette->get_num_blends();
|
||||
int bi;
|
||||
for (bi = 0; bi < num_blends; bi++) {
|
||||
palette->get_blend(bi).update_blend();
|
||||
if (cdata->_animated_vertices == (qpGeomVertexData *)NULL) {
|
||||
CPT(qpGeomVertexFormat) animated_format = get_post_animated_format();
|
||||
cdata->_animated_vertices =
|
||||
new qpGeomVertexData(get_name(), animated_format,
|
||||
min(get_usage_hint(), qpGeomUsageHint::UH_dynamic));
|
||||
}
|
||||
|
||||
PT(qpGeomVertexData) new_data = cdata->_animated_vertices;
|
||||
|
||||
// Now go through and compute the animation.
|
||||
qpGeomVertexWriter to(new_data, InternalName::get_vertex());
|
||||
qpGeomVertexReader from(this, InternalName::get_vertex());
|
||||
qpGeomVertexReader blendi(this, InternalName::get_transform_blend());
|
||||
// We have to make a complete copy of data first so we can modify
|
||||
// it. If we were clever, we could maybe just figure out the subset
|
||||
// of the data that might have changed since last frame, but that's
|
||||
// too much trouble (and isn't obviously faster than just copying
|
||||
// the whole thing).
|
||||
new_data->copy_from(*this, true);
|
||||
|
||||
if (!blendi.has_data_type()) {
|
||||
gobj_cat.warning()
|
||||
<< "Vertex data " << get_name()
|
||||
<< " has a transform_blend_palette, but no transform_blend data.\n";
|
||||
return;
|
||||
}
|
||||
// First, apply all of the morphs.
|
||||
CPT(SliderTable) table = cdata->_slider_table;
|
||||
if (table != (SliderTable *)NULL) {
|
||||
int num_morphs = _format->get_num_morphs();
|
||||
for (int mi = 0; mi < num_morphs; mi++) {
|
||||
CPT(InternalName) slider_name = _format->get_morph_slider(mi);
|
||||
const VertexSlider *slider = table->get_slider(slider_name);
|
||||
if (slider != (VertexSlider *)NULL) {
|
||||
float slider_value = slider->get_slider();
|
||||
if (slider_value != 0.0f) {
|
||||
CPT(InternalName) base_name = _format->get_morph_base(mi);
|
||||
CPT(InternalName) delta_name = _format->get_morph_delta(mi);
|
||||
|
||||
qpGeomVertexRewriter data(new_data, base_name);
|
||||
qpGeomVertexReader delta(this, delta_name);
|
||||
|
||||
if (from.get_data_type()->get_num_values() == 4) {
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
LPoint4f vertex = from.get_data4f();
|
||||
int bi = blendi.get_data1i();
|
||||
palette->get_blend(bi).transform_point(vertex);
|
||||
to.set_data4f(vertex);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
LPoint3f vertex = from.get_data3f();
|
||||
int bi = blendi.get_data1i();
|
||||
palette->get_blend(bi).transform_point(vertex);
|
||||
to.set_data3f(vertex);
|
||||
if (data.get_data_type()->get_num_values() == 4) {
|
||||
if (data.get_data_type()->has_homogeneous_coord()) {
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
// Scale the delta by the homogeneous coordinate.
|
||||
LPoint4f vertex = data.get_data4f();
|
||||
LPoint3f d = delta.get_data3f();
|
||||
d *= slider_value * vertex[3];
|
||||
data.set_data4f(vertex[0] + d[0],
|
||||
vertex[1] + d[1],
|
||||
vertex[2] + d[2],
|
||||
vertex[3]);
|
||||
}
|
||||
} else {
|
||||
// Just apply the four-component delta.
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
const LPoint4f &vertex = data.get_data4f();
|
||||
LPoint4f d = delta.get_data4f();
|
||||
data.set_data4f(vertex + d * slider_value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 3-component or smaller values; don't worry about a
|
||||
// homogeneous coordinate.
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
const LPoint3f &vertex = data.get_data3f();
|
||||
LPoint3f d = delta.get_data3f();
|
||||
data.set_data3f(vertex + d * slider_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Then apply the transforms.
|
||||
CPT(TransformBlendPalette) palette = cdata->_transform_blend_palette;
|
||||
if (palette != (TransformBlendPalette *)NULL) {
|
||||
|
||||
// Recompute all the blends up front, so we don't have to test
|
||||
// each one for staleness at each vertex.
|
||||
int num_blends = palette->get_num_blends();
|
||||
int bi;
|
||||
for (bi = 0; bi < num_blends; bi++) {
|
||||
palette->get_blend(bi).update_blend();
|
||||
}
|
||||
|
||||
// Now go through and apply the transforms.
|
||||
qpGeomVertexRewriter data(new_data, InternalName::get_vertex());
|
||||
qpGeomVertexReader blendi(this, InternalName::get_transform_blend());
|
||||
|
||||
if (!blendi.has_data_type()) {
|
||||
gobj_cat.warning()
|
||||
<< "Vertex data " << get_name()
|
||||
<< " has a transform_blend_palette, but no transform_blend data.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.get_data_type()->get_num_values() == 4) {
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
LPoint4f vertex = data.get_data4f();
|
||||
int bi = blendi.get_data1i();
|
||||
palette->get_blend(bi).transform_point(vertex);
|
||||
data.set_data4f(vertex);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < num_vertices; i++) {
|
||||
LPoint3f vertex = data.get_data3f();
|
||||
int bi = blendi.get_data1i();
|
||||
palette->get_blend(bi).transform_point(vertex);
|
||||
data.set_data3f(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexData::get_post_animated_format
|
||||
// Access: Private
|
||||
// Description: Returns a suitable vertex format for sending the
|
||||
// animated vertices to the graphics backend. This is
|
||||
// the same format as the source format, with the
|
||||
// CPU-animation data elements removed.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CPT(qpGeomVertexFormat) qpGeomVertexData::
|
||||
get_post_animated_format() const {
|
||||
PT(qpGeomVertexFormat) new_format = new qpGeomVertexFormat(*_format);
|
||||
|
||||
new_format->remove_data_type(InternalName::get_transform_blend());
|
||||
|
||||
int num_morphs = _format->get_num_morphs();
|
||||
for (int mi = 0; mi < num_morphs; mi++) {
|
||||
CPT(InternalName) delta_name = _format->get_morph_delta(mi);
|
||||
new_format->remove_data_type(delta_name);
|
||||
}
|
||||
|
||||
return qpGeomVertexFormat::register_format(new_format);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include "qpgeomVertexArrayData.h"
|
||||
#include "qpgeomUsageHint.h"
|
||||
#include "transformBlendPalette.h"
|
||||
#include "sliderTable.h"
|
||||
#include "internalName.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
|
|
@ -91,9 +92,15 @@ PUBLISHED:
|
|||
void set_transform_blend_palette(const TransformBlendPalette *palette);
|
||||
INLINE void clear_transform_blend_palette();
|
||||
|
||||
INLINE const SliderTable *get_slider_table() const;
|
||||
SliderTable *modify_slider_table();
|
||||
void set_slider_table(const SliderTable *palette);
|
||||
INLINE void clear_slider_table();
|
||||
|
||||
int get_num_bytes() const;
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
void copy_from(const qpGeomVertexData &source, bool keep_data_objects);
|
||||
CPT(qpGeomVertexData) convert_to(const qpGeomVertexFormat *new_format) const;
|
||||
CPT(qpGeomVertexData)
|
||||
scale_color(const LVecBase4f &color_scale, int num_components,
|
||||
|
|
@ -167,6 +174,7 @@ private:
|
|||
|
||||
Arrays _arrays;
|
||||
PT(TransformBlendPalette) _transform_blend_palette;
|
||||
PT(SliderTable) _slider_table;
|
||||
PT(qpGeomVertexData) _animated_vertices;
|
||||
UpdateSeq _animated_vertices_modified;
|
||||
UpdateSeq _modified;
|
||||
|
|
@ -178,8 +186,8 @@ private:
|
|||
|
||||
private:
|
||||
bool do_set_num_vertices(int n, CDWriter &cdata);
|
||||
void make_animated_vertices(CDWriter &cdata);
|
||||
void update_animated_vertices(CDWriter &cdata, bool from_app);
|
||||
CPT(qpGeomVertexFormat) get_post_animated_format() const;
|
||||
|
||||
static PStatCollector _convert_pcollector;
|
||||
static PStatCollector _scale_color_pcollector;
|
||||
|
|
|
|||
|
|
@ -151,6 +151,30 @@ get_total_bytes() const {
|
|||
return _total_bytes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexDataType::has_homogeneous_coord
|
||||
// Access: Published
|
||||
// Description: Returns true if this Contents type is one that
|
||||
// includes a homogeneous coordinate in the fourth
|
||||
// component, or false otherwise. If this is true,
|
||||
// correct operation on the vertex data may require
|
||||
// scaling by the homogeneous coordinate from time to
|
||||
// time (but in general this is handled automatically if
|
||||
// you use the 3-component or smaller forms of
|
||||
// get_data() and set_data()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool qpGeomVertexDataType::
|
||||
has_homogeneous_coord() const {
|
||||
switch (_contents) {
|
||||
case C_point:
|
||||
case C_texcoord:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexDataType::overlaps_with
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ PUBLISHED:
|
|||
C_rgba, // RGB or RGBA, OpenGL-style order
|
||||
C_argb, // RGBA, DirectX-style packed color
|
||||
C_index, // An index value into some other table
|
||||
C_morph_delta, // A delta from some base value, defining a blend shape
|
||||
};
|
||||
|
||||
INLINE qpGeomVertexDataType(const InternalName *name, int num_components,
|
||||
|
|
@ -67,6 +68,7 @@ PUBLISHED:
|
|||
INLINE int get_start() const;
|
||||
INLINE int get_component_bytes() const;
|
||||
INLINE int get_total_bytes() const;
|
||||
INLINE bool has_homogeneous_coord() const;
|
||||
|
||||
INLINE bool overlaps_with(int start_byte, int num_bytes) const;
|
||||
INLINE bool is_bytewise_equivalent(const qpGeomVertexDataType &other) const;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,81 @@ get_array(int array) const {
|
|||
return _arrays[array];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexFormat::get_num_morphs
|
||||
// Access: Published
|
||||
// Description: Returns the number of data types within the format
|
||||
// that represent morph deltas.
|
||||
//
|
||||
// This may only be called after the format has been
|
||||
// registered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int qpGeomVertexFormat::
|
||||
get_num_morphs() const {
|
||||
nassertr(_is_registered, 0);
|
||||
|
||||
return _morphs.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexFormat::get_morph_slider
|
||||
// Access: Published
|
||||
// Description: Returns the slider name associated with the nth morph
|
||||
// data type. This is the name of the slider that will
|
||||
// control the morph, and should be defined within the
|
||||
// SliderTable associated with the GeomVertexData.
|
||||
//
|
||||
// This may only be called after the format has been
|
||||
// registered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const InternalName *qpGeomVertexFormat::
|
||||
get_morph_slider(int n) const {
|
||||
nassertr(_is_registered, NULL);
|
||||
nassertr(n >= 0 && n < (int)_morphs.size(), NULL);
|
||||
|
||||
return _morphs[n]._slider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexFormat::get_morph_base
|
||||
// Access: Published
|
||||
// Description: Returns the name of the base data type that the nth
|
||||
// morph modifies. This data type will also be defined
|
||||
// within the format, and can be retrieved via
|
||||
// get_array_with() and/or get_data_type().
|
||||
//
|
||||
// This may only be called after the format has been
|
||||
// registered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const InternalName *qpGeomVertexFormat::
|
||||
get_morph_base(int n) const {
|
||||
nassertr(_is_registered, NULL);
|
||||
nassertr(n >= 0 && n < (int)_morphs.size(), NULL);
|
||||
|
||||
return _morphs[n]._base;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexFormat::get_morph_delta
|
||||
// Access: Published
|
||||
// Description: Returns the name of the data type that defines the
|
||||
// nth morph. This contains the delta offsets that are
|
||||
// to be applied to the data type defined by
|
||||
// get_morph_base(). This data type will be defined
|
||||
// within the format, and can be retrieved via
|
||||
// get_array_with() and/or get_data_type().
|
||||
//
|
||||
// This may only be called after the format has been
|
||||
// registered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const InternalName *qpGeomVertexFormat::
|
||||
get_morph_delta(int n) const {
|
||||
nassertr(_is_registered, NULL);
|
||||
nassertr(n >= 0 && n < (int)_morphs.size(), NULL);
|
||||
|
||||
return _morphs[n]._delta;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: qpGeomVertexFormat::get_v3
|
||||
// Access: Published, Static
|
||||
|
|
|
|||
|
|
@ -506,6 +506,42 @@ do_register() {
|
|||
}
|
||||
}
|
||||
|
||||
// Go back through the index now and look for morph descriptions.
|
||||
DataTypesByName::iterator ni;
|
||||
for (ni = _data_types_by_name.begin();
|
||||
ni != _data_types_by_name.end();
|
||||
++ni) {
|
||||
const DataTypeRecord &record = (*ni).second;
|
||||
const qpGeomVertexDataType *data_type = _arrays[record._array_index]->get_data_type(record._data_type_index);
|
||||
|
||||
// Is it a morph description?
|
||||
if (data_type->get_contents() == qpGeomVertexDataType::C_morph_delta) {
|
||||
MorphRecord morph;
|
||||
morph._delta = data_type->get_name();
|
||||
|
||||
// The delta name must be of the form "basename.morph.slidername".
|
||||
int n = morph._delta->find_ancestor("morph");
|
||||
if (n < 0) {
|
||||
gobj_cat.warning()
|
||||
<< "vertex format defines " << *data_type->get_name()
|
||||
<< ", which is stored as a C_morph_delta, but its name does not include \"morph\".\n";
|
||||
} else {
|
||||
morph._slider = InternalName::make(morph._delta->get_net_basename(n - 1));
|
||||
morph._base = morph._delta->get_ancestor(n + 1);
|
||||
|
||||
if (_data_types_by_name.find(morph._base) == _data_types_by_name.end()) {
|
||||
gobj_cat.warning()
|
||||
<< "vertex format defines "
|
||||
<< *data_type->get_name() << " but does not define "
|
||||
<< *morph._base << "\n";
|
||||
} else {
|
||||
_morphs.push_back(morph);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_is_registered = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -84,6 +84,11 @@ PUBLISHED:
|
|||
|
||||
void remove_data_type(const InternalName *name);
|
||||
|
||||
INLINE int get_num_morphs() const;
|
||||
INLINE const InternalName *get_morph_slider(int n) const;
|
||||
INLINE const InternalName *get_morph_base(int n) const;
|
||||
INLINE const InternalName *get_morph_delta(int n) const;
|
||||
|
||||
void output(ostream &out) const;
|
||||
void write(ostream &out, int indent_level = 0) const;
|
||||
void write_with_data(ostream &out, int indent_level,
|
||||
|
|
@ -146,6 +151,15 @@ private:
|
|||
typedef pmap<const InternalName *, DataTypeRecord> DataTypesByName;
|
||||
DataTypesByName _data_types_by_name;
|
||||
|
||||
class MorphRecord {
|
||||
public:
|
||||
CPT(InternalName) _slider;
|
||||
CPT(InternalName) _base;
|
||||
CPT(InternalName) _delta;
|
||||
};
|
||||
typedef pvector<MorphRecord> Morphs;
|
||||
Morphs _morphs;
|
||||
|
||||
// This set keeps track of things that need to be told when we
|
||||
// destruct, and it is protected by the mutex.
|
||||
Mutex _cache_lock;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
// Filename: sliderTable.I
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::is_registered
|
||||
// Access: Published
|
||||
// Description: Returns true if this table has been registered.
|
||||
// Once it has been registered, the set of sliders in
|
||||
// a SliderTable may not be further modified; but
|
||||
// it must be registered before it can be assigned to a
|
||||
// Geom.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool SliderTable::
|
||||
is_registered() const {
|
||||
return _is_registered;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::register_table
|
||||
// Access: Published, Static
|
||||
// Description: Registers a SliderTable for use. This is
|
||||
// similar to GeomVertexFormat::register_format(). Once
|
||||
// registered, a SliderTable may no longer be
|
||||
// modified (although the individual VertexSlider
|
||||
// objects may modify their reported sliders).
|
||||
//
|
||||
// This must be called before a table may be used in a
|
||||
// Geom. After this call, you should discard the
|
||||
// original pointer you passed in (which may or may not
|
||||
// now be invalid) and let its reference count decrement
|
||||
// normally; you should use only the returned value from
|
||||
// this point on.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE CPT(SliderTable) SliderTable::
|
||||
register_table(SliderTable *table) {
|
||||
// We don't actually bother adding the table object to a registry.
|
||||
// This means there may be multiple copies of identical registered
|
||||
// SliderTables. Big deal. We can always go back and make a
|
||||
// registry later if we really need it.
|
||||
if (table->is_registered()) {
|
||||
return table;
|
||||
}
|
||||
|
||||
table->do_register();
|
||||
return table;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::get_slider
|
||||
// Access: Published
|
||||
// Description: Returns the slider with the indicated name, or NULL
|
||||
// if no slider in the table has that name.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const VertexSlider *SliderTable::
|
||||
get_slider(const InternalName *name) const {
|
||||
Sliders::const_iterator si;
|
||||
si = _sliders.find(name);
|
||||
if (si != _sliders.end()) {
|
||||
return (*si).second;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::get_modified
|
||||
// Access: Published
|
||||
// Description: Returns a sequence number that's guaranteed to change
|
||||
// at least when any VertexSliders in the table
|
||||
// change. (However, this is only true for a registered
|
||||
// table. An unregistered table may or may not
|
||||
// reflect an update here when a VertexSlider
|
||||
// changes.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UpdateSeq SliderTable::
|
||||
get_modified() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::update_modified
|
||||
// Access: Private
|
||||
// Description: Called internally whenever a nested VertexSlider
|
||||
// reports that it has been modified.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void SliderTable::
|
||||
update_modified(UpdateSeq modified) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_modified = modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::CData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SliderTable::CData::
|
||||
CData() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::CData::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE SliderTable::CData::
|
||||
CData(const SliderTable::CData ©) :
|
||||
_modified(copy._modified)
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
// Filename: sliderTable.cxx
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "sliderTable.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
||||
TypeHandle SliderTable::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SliderTable::
|
||||
SliderTable() :
|
||||
_is_registered(false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::Copy Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SliderTable::
|
||||
SliderTable(const SliderTable ©) :
|
||||
_is_registered(false),
|
||||
_sliders(copy._sliders)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::Copy Assignment Operator
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
operator = (const SliderTable ©) {
|
||||
nassertv(!_is_registered);
|
||||
_sliders = copy._sliders;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
SliderTable::
|
||||
~SliderTable() {
|
||||
if (_is_registered) {
|
||||
do_unregister();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::remove_slider
|
||||
// Access: Published
|
||||
// Description: Removes the named slider. Only valid for
|
||||
// unregistered tables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
remove_slider(const InternalName *name) {
|
||||
nassertv(!_is_registered);
|
||||
|
||||
Sliders::iterator si = _sliders.find(name);
|
||||
if (si != _sliders.end()) {
|
||||
_sliders.erase(si);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::add_slider
|
||||
// Access: Published
|
||||
// Description: Adds a new slider to the table, or replaces an
|
||||
// existing slider with the same name. Only valid for
|
||||
// unregistered tables.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
add_slider(VertexSlider *slider) {
|
||||
nassertv(!_is_registered);
|
||||
|
||||
_sliders[slider->get_name()] = slider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::write
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
write(ostream &out) const {
|
||||
Sliders::const_iterator si;
|
||||
for (si = _sliders.begin(); si != _sliders.end(); ++si) {
|
||||
out << *(*si).second << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::do_register
|
||||
// Access: Private
|
||||
// Description: Called internally when the table is registered.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
do_register() {
|
||||
nassertv(!_is_registered);
|
||||
|
||||
Sliders::iterator si;
|
||||
for (si = _sliders.begin(); si != _sliders.end(); ++si) {
|
||||
bool inserted = (*si).second->_tables.insert(this).second;
|
||||
nassertv(inserted);
|
||||
}
|
||||
_is_registered = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::do_unregister
|
||||
// Access: Private
|
||||
// Description: Called internally when the table is unregistered
|
||||
// (i.e. right before destruction).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
do_unregister() {
|
||||
nassertv(_is_registered);
|
||||
|
||||
Sliders::iterator si;
|
||||
for (si = _sliders.begin(); si != _sliders.end(); ++si) {
|
||||
(*si).second->_tables.erase(this);
|
||||
}
|
||||
_is_registered = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
// Description: Tells the BamReader how to create objects of type
|
||||
// SliderTable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
TypedWritable::write_datagram(manager, dg);
|
||||
|
||||
manager->write_cdata(dg, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::make_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: This function is called by the BamReader's factory
|
||||
// when a new object of type SliderTable is encountered
|
||||
// in the Bam file. It should create the SliderTable
|
||||
// and extract its information from the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *SliderTable::
|
||||
make_from_bam(const FactoryParams ¶ms) {
|
||||
SliderTable *object = new SliderTable;
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
||||
parse_params(params, scan, manager);
|
||||
object->fillin(scan, manager);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::fillin
|
||||
// Access: Protected
|
||||
// Description: This internal function is called by make_from_bam to
|
||||
// read in all of the relevant data from the BamFile for
|
||||
// the new SliderTable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
TypedWritable::fillin(scan, manager);
|
||||
|
||||
manager->read_cdata(scan, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *SliderTable::CData::
|
||||
make_copy() const {
|
||||
return new CData(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::CData::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::CData::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::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 SliderTable::CData::
|
||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||
int pi = CycleData::complete_pointers(p_list, manager);
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: SliderTable::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 SliderTable.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void SliderTable::CData::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
// Filename: sliderTable.h
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef SLIDERTABLE_H
|
||||
#define SLIDERTABLE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "vertexSlider.h"
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "pointerTo.h"
|
||||
#include "pmap.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
#include "pipelineCycler.h"
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : SliderTable
|
||||
// Description : Stores the total set of VertexSliders that the
|
||||
// vertices in a particular GeomVertexData object might
|
||||
// depend on.
|
||||
//
|
||||
// This is similar to a TransformPalette, but it stores
|
||||
// VertexSliders instead of VertexTransforms, and it
|
||||
// stores them by name instead of by index number.
|
||||
// Also, it is only used when animating vertices on the
|
||||
// CPU, since GPU's don't support morphs at this point
|
||||
// in time.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA SliderTable : public TypedWritableReferenceCount {
|
||||
PUBLISHED:
|
||||
SliderTable();
|
||||
SliderTable(const SliderTable ©);
|
||||
void operator = (const SliderTable ©);
|
||||
virtual ~SliderTable();
|
||||
|
||||
INLINE bool is_registered() const;
|
||||
INLINE static CPT(SliderTable) register_table(SliderTable *table);
|
||||
|
||||
INLINE const VertexSlider *get_slider(const InternalName *name) const;
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
void remove_slider(const InternalName *name);
|
||||
void add_slider(VertexSlider *slider);
|
||||
|
||||
void write(ostream &out) const;
|
||||
|
||||
private:
|
||||
void do_register();
|
||||
void do_unregister();
|
||||
INLINE void update_modified(UpdateSeq modified);
|
||||
|
||||
private:
|
||||
bool _is_registered;
|
||||
|
||||
typedef pmap< const InternalName *, PT(VertexSlider) > Sliders;
|
||||
Sliders _sliders;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
INLINE CData();
|
||||
INLINE CData(const CData ©);
|
||||
virtual CycleData *make_copy() const;
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
|
||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
UpdateSeq _modified;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
||||
protected:
|
||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
TypedWritableReferenceCount::init_type();
|
||||
register_type(_type_handle, "SliderTable",
|
||||
TypedWritableReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class VertexSlider;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const SliderTable &obj);
|
||||
|
||||
#include "sliderTable.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -105,9 +105,9 @@ get_modified() const {
|
|||
// reports that it has been modified.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void TransformPalette::
|
||||
update_modified(UpdateSeq) {
|
||||
update_modified(UpdateSeq modified) {
|
||||
CDWriter cdata(_cycler);
|
||||
++(cdata->_modified);
|
||||
cdata->_modified = modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
// Filename: userVertexSlider.I
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::set_slider
|
||||
// Access: Published
|
||||
// Description: Stores the indicated slider value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void UserVertexSlider::
|
||||
set_slider(float slider) {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_slider = slider;
|
||||
mark_modified();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::CData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UserVertexSlider::CData::
|
||||
CData() :
|
||||
_slider(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::CData::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UserVertexSlider::CData::
|
||||
CData(const UserVertexSlider::CData ©) :
|
||||
_slider(copy._slider)
|
||||
{
|
||||
}
|
||||
|
|
@ -0,0 +1,145 @@
|
|||
// Filename: userVertexSlider.cxx
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "userVertexSlider.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
|
||||
TypeHandle UserVertexSlider::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
UserVertexSlider::
|
||||
UserVertexSlider(const string &name) :
|
||||
VertexSlider(InternalName::make(name))
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
UserVertexSlider::
|
||||
UserVertexSlider(const InternalName *name) :
|
||||
VertexSlider(name)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::get_slider
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns the current slider value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
float UserVertexSlider::
|
||||
get_slider() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_slider;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *UserVertexSlider::CData::
|
||||
make_copy() const {
|
||||
return new CData(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::register_with_read_factory
|
||||
// Access: Public, Static
|
||||
// Description: Tells the BamReader how to create objects of type
|
||||
// UserVertexSlider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexSlider::
|
||||
register_with_read_factory() {
|
||||
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexSlider::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
VertexSlider::write_datagram(manager, dg);
|
||||
|
||||
manager->write_cdata(dg, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::make_from_bam
|
||||
// Access: Protected, Static
|
||||
// Description: This function is called by the BamReader's factory
|
||||
// when a new object of type UserVertexSlider is encountered
|
||||
// in the Bam file. It should create the UserVertexSlider
|
||||
// and extract its information from the file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable *UserVertexSlider::
|
||||
make_from_bam(const FactoryParams ¶ms) {
|
||||
UserVertexSlider *object = new UserVertexSlider("");
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
||||
parse_params(params, scan, manager);
|
||||
object->fillin(scan, manager);
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::fillin
|
||||
// Access: Protected
|
||||
// Description: This internal function is called by make_from_bam to
|
||||
// read in all of the relevant data from the BamFile for
|
||||
// the new UserVertexSlider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexSlider::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
VertexSlider::fillin(scan, manager);
|
||||
|
||||
manager->read_cdata(scan, _cycler);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::CData::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexSlider::CData::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: UserVertexSlider::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 UserVertexSlider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexSlider::CData::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
}
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
// Filename: userVertexSlider.h
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef USERVERTEXSLIDER_H
|
||||
#define USERVERTEXSLIDER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "vertexSlider.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
#include "pipelineCycler.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : UserVertexSlider
|
||||
// Description : This is a specialization on VertexSlider that
|
||||
// allows the user to specify any arbitrary slider
|
||||
// valie he likes. This is rarely used except for
|
||||
// testing.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA UserVertexSlider : public VertexSlider {
|
||||
PUBLISHED:
|
||||
UserVertexSlider(const string &name);
|
||||
UserVertexSlider(const InternalName *name);
|
||||
|
||||
INLINE void set_slider(float slider);
|
||||
virtual float get_slider() const;
|
||||
|
||||
private:
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
INLINE CData();
|
||||
INLINE CData(const CData ©);
|
||||
virtual CycleData *make_copy() const;
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
float _slider;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
public:
|
||||
static void register_with_read_factory();
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
||||
protected:
|
||||
static TypedWritable *make_from_bam(const FactoryParams ¶ms);
|
||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
VertexSlider::init_type();
|
||||
register_type(_type_handle, "UserVertexSlider",
|
||||
VertexSlider::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#include "userVertexSlider.I"
|
||||
|
||||
#endif
|
||||
|
|
@ -51,7 +51,7 @@ get_matrix(LMatrix4f &matrix) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void UserVertexTransform::
|
||||
output(ostream &out) const {
|
||||
out << get_name();
|
||||
out << get_type() << " " << get_name();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -0,0 +1,70 @@
|
|||
// Filename: vertexSlider.I
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::get_name
|
||||
// Access: Published
|
||||
// Description: Returns the name of this particular slider. Every
|
||||
// unique blend shape within a particular Geom must be
|
||||
// identified with a different name, which is shared by
|
||||
// the slider that controls it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const InternalName *VertexSlider::
|
||||
get_name() const {
|
||||
return _name;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::get_modified
|
||||
// Access: Published
|
||||
// Description: Returns a sequence number that's guaranteed to change
|
||||
// at least every time the value reported by
|
||||
// get_slider() changes.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE UpdateSeq VertexSlider::
|
||||
get_modified() const {
|
||||
CDReader cdata(_cycler);
|
||||
return cdata->_modified;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::CData::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE VertexSlider::CData::
|
||||
CData() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::CData::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE VertexSlider::CData::
|
||||
CData(const VertexSlider::CData ©) :
|
||||
_modified(copy._modified)
|
||||
{
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const VertexSlider &obj) {
|
||||
obj.output(out);
|
||||
return out;
|
||||
}
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
// Filename: vertexSlider.cxx
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "vertexSlider.h"
|
||||
#include "vertexTransform.h"
|
||||
#include "bamReader.h"
|
||||
#include "bamWriter.h"
|
||||
#include "indent.h"
|
||||
|
||||
TypeHandle VertexSlider::_type_handle;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::Constructor
|
||||
// Access: Published
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexSlider::
|
||||
VertexSlider(const InternalName *name) : _name(name) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::Destructor
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
VertexSlider::
|
||||
~VertexSlider() {
|
||||
// We shouldn't destruct while any SliderTables are holding our
|
||||
// pointer.
|
||||
nassertv(_tables.empty());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::output
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::
|
||||
output(ostream &out) const {
|
||||
out << get_type() << " " << get_name();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::write
|
||||
// Access: Published, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::
|
||||
write(ostream &out, int indent_level) const {
|
||||
indent(out, indent_level)
|
||||
<< *this << " = " << get_slider() << "\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::mark_modified
|
||||
// Access: Protected
|
||||
// Description: Intended to be called by a derived class whenever the
|
||||
// reported transform might have changed. Without
|
||||
// calling this method, changes to get_slider() may not
|
||||
// be propagated through the system.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::
|
||||
mark_modified() {
|
||||
CDWriter cdata(_cycler);
|
||||
cdata->_modified = VertexTransform::get_next_modified();
|
||||
|
||||
Tables::iterator ti;
|
||||
for (ti = _tables.begin(); ti != _tables.end(); ++ti) {
|
||||
(*ti)->update_modified(cdata->_modified);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) {
|
||||
TypedWritable::write_datagram(manager, dg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::fillin
|
||||
// Access: Protected
|
||||
// Description: This internal function is called by make_from_bam to
|
||||
// read in all of the relevant data from the BamFile for
|
||||
// the new VertexSlider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
TypedWritable::fillin(scan, manager);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::CData::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
CycleData *VertexSlider::CData::
|
||||
make_copy() const {
|
||||
return new CData(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::CData::write_datagram
|
||||
// Access: Public, Virtual
|
||||
// Description: Writes the contents of this object to the datagram
|
||||
// for shipping out to a Bam file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::CData::
|
||||
write_datagram(BamWriter *manager, Datagram &dg) const {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::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 VertexSlider::CData::
|
||||
complete_pointers(TypedWritable **p_list, BamReader *manager) {
|
||||
int pi = CycleData::complete_pointers(p_list, manager);
|
||||
|
||||
return pi;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: VertexSlider::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 VertexSlider.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void VertexSlider::CData::
|
||||
fillin(DatagramIterator &scan, BamReader *manager) {
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
// Filename: vertexSlider.h
|
||||
// Created by: drose (28Mar05)
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PANDA 3D SOFTWARE
|
||||
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
||||
//
|
||||
// All use of this software is subject to the terms of the Panda 3d
|
||||
// Software license. You should have received a copy of this license
|
||||
// along with this source code; you will also find a current copy of
|
||||
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
||||
//
|
||||
// To contact the maintainers of this program write to
|
||||
// panda3d-general@lists.sourceforge.net .
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef VERTEXSLIDER_H
|
||||
#define VERTEXSLIDER_H
|
||||
|
||||
#include "pandabase.h"
|
||||
#include "typedWritableReferenceCount.h"
|
||||
#include "internalName.h"
|
||||
#include "updateSeq.h"
|
||||
#include "pset.h"
|
||||
#include "cycleData.h"
|
||||
#include "cycleDataReader.h"
|
||||
#include "cycleDataWriter.h"
|
||||
#include "pipelineCycler.h"
|
||||
|
||||
class SliderTable;
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : VertexSlider
|
||||
// Description : This is an abstract base class that retains some
|
||||
// slider value, which is a linear value that typically
|
||||
// ranges from 0.0 to 1.0, and is used to control the
|
||||
// animation of morphs (blend shapes).
|
||||
//
|
||||
// It is similar to VertexTransform, which keeps a full
|
||||
// 4x4 transform matrix, but the VertexSlider only keeps
|
||||
// a single float value.
|
||||
//
|
||||
// This is part of the experimental Geom rewrite.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA VertexSlider : public TypedWritableReferenceCount {
|
||||
PUBLISHED:
|
||||
VertexSlider(const InternalName *name);
|
||||
virtual ~VertexSlider();
|
||||
|
||||
INLINE const InternalName *get_name() const;
|
||||
|
||||
virtual float get_slider() const=0;
|
||||
INLINE UpdateSeq get_modified() const;
|
||||
|
||||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
protected:
|
||||
void mark_modified();
|
||||
|
||||
private:
|
||||
CPT(InternalName) _name;
|
||||
|
||||
typedef pset<SliderTable *> Tables;
|
||||
Tables _tables;
|
||||
|
||||
// This is the data that must be cycled between pipeline stages.
|
||||
class EXPCL_PANDA CData : public CycleData {
|
||||
public:
|
||||
INLINE CData();
|
||||
INLINE CData(const CData ©);
|
||||
virtual CycleData *make_copy() const;
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
|
||||
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
UpdateSeq _modified;
|
||||
};
|
||||
|
||||
PipelineCycler<CData> _cycler;
|
||||
typedef CycleDataReader<CData> CDReader;
|
||||
typedef CycleDataWriter<CData> CDWriter;
|
||||
|
||||
static PipelineCycler<CData> _global_cycler;
|
||||
static UpdateSeq _next_modified;
|
||||
|
||||
public:
|
||||
virtual void write_datagram(BamWriter *manager, Datagram &dg);
|
||||
|
||||
protected:
|
||||
void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
TypedWritableReferenceCount::init_type();
|
||||
register_type(_type_handle, "VertexSlider",
|
||||
TypedWritableReferenceCount::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
|
||||
friend class SliderTable;
|
||||
};
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const VertexSlider &obj);
|
||||
|
||||
#include "vertexSlider.I"
|
||||
|
||||
#endif
|
||||
Loading…
Reference in New Issue