From 5ba9232349eb33c4953b344f50bb3cd0ceaef261 Mon Sep 17 00:00:00 2001 From: David Rose Date: Sun, 27 Mar 2005 19:02:40 +0000 Subject: [PATCH] use GeomVertexReader/Writer to implement convert_to() --- panda/src/gobj/qpgeomVertexData.cxx | 163 +++++++++++++++- panda/src/gobj/qpgeomVertexData.h | 14 ++ panda/src/gobj/qpgeomVertexDataType.I | 44 +++++ panda/src/gobj/qpgeomVertexDataType.cxx | 240 ------------------------ panda/src/gobj/qpgeomVertexDataType.h | 33 +--- 5 files changed, 218 insertions(+), 276 deletions(-) diff --git a/panda/src/gobj/qpgeomVertexData.cxx b/panda/src/gobj/qpgeomVertexData.cxx index dac674e8e4..3b99dd34de 100644 --- a/panda/src/gobj/qpgeomVertexData.cxx +++ b/panda/src/gobj/qpgeomVertexData.cxx @@ -327,19 +327,62 @@ convert_to(const qpGeomVertexFormat *new_format) const { 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. - PTA_uchar new_array_data = - new_data->modify_array(new_i)->modify_data(); - 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()); - new_data_type->copy_records - (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); + 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"; + } + qpGeomVertexReader from(this); + from.set_data_type(i, data_type); + qpGeomVertexWriter to(new_data); + to.set_data_type(new_i, new_data_type); + + while (!from.is_at_end()) { + to.set_data4f(from.get_data4f()); + } + } } } } @@ -630,6 +673,110 @@ get_array_info(const InternalName *name, return false; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::bytewise_copy +// Access: Private, Static +// Description: Quickly copies data without the need to convert it. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexData:: +bytewise_copy(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + const qpGeomVertexDataType *from_type, + int num_records) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "bytewise_copy(" << (void *)to << ", " << to_stride + << ", " << (const void *)from << ", " << from_stride + << ", " << *from_type << ", " << num_records << ")\n"; + } + if (to_stride == from_type->get_total_bytes() && + from_stride == from_type->get_total_bytes()) { + // Fantastic! It's just a linear array of this one data type. + // Copy the whole thing all at once. + memcpy(to, from, num_records * from_type->get_total_bytes()); + + } else { + // Ok, it's interleaved in with other data. Copy them one record + // at a time. + while (num_records > 0) { + memcpy(to, from, from_type->get_total_bytes()); + to += to_stride; + from += from_stride; + num_records--; + } + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::packed_argb_to_uint8_rgba +// Access: Private, Static +// Description: Quickly converts DirectX-style color to OpenGL-style +// color. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexData:: +packed_argb_to_uint8_rgba(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + int num_records) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "packed_argb_to_uint8_rgba(" << (void *)to << ", " << to_stride + << ", " << (const void *)from << ", " << from_stride + << ", " << num_records << ")\n"; + } + typedef union { + unsigned char _b[4]; + PN_uint32 _i; + } packed_8888; + + while (num_records > 0) { + packed_8888 dword; + dword._i = *(const PN_uint32 *)from; + to[0] = dword._b[1]; + to[1] = dword._b[2]; + to[2] = dword._b[3]; + to[3] = dword._b[0]; + + to += to_stride; + from += from_stride; + num_records--; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::uint8_rgba_to_packed_argb +// Access: Private, Static +// Description: Quickly converts OpenGL-style color to DirectX-style +// color. +//////////////////////////////////////////////////////////////////// +void qpGeomVertexData:: +uint8_rgba_to_packed_argb(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + int num_records) { + if (gobj_cat.is_debug()) { + gobj_cat.debug() + << "uint8_rgba_to_packed_argb(" << (void *)to << ", " << to_stride + << ", " << (const void *)from << ", " << from_stride + << ", " << num_records << ")\n"; + } + typedef union { + unsigned char _b[4]; + PN_uint32 _i; + } packed_8888; + + while (num_records > 0) { + packed_8888 dword; + dword._b[0] = from[3]; + dword._b[1] = from[0]; + dword._b[2] = from[1]; + dword._b[3] = from[2]; + *(PN_uint32 *)to = dword._i; + + to += to_stride; + from += from_stride; + num_records--; + } +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomVertexData::do_set_num_vertices // Access: Private diff --git a/panda/src/gobj/qpgeomVertexData.h b/panda/src/gobj/qpgeomVertexData.h index 57c66d8f60..3acbd14ae7 100644 --- a/panda/src/gobj/qpgeomVertexData.h +++ b/panda/src/gobj/qpgeomVertexData.h @@ -123,6 +123,20 @@ public: qpGeomVertexDataType::NumericType &numeric_type, int &start, int &stride) const; +private: + static void bytewise_copy(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + const qpGeomVertexDataType *from_type, + int num_records); + static void + packed_argb_to_uint8_rgba(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + int num_records); + static void + uint8_rgba_to_packed_argb(unsigned char *to, int to_stride, + const unsigned char *from, int from_stride, + int num_records); + private: string _name; CPT(qpGeomVertexFormat) _format; diff --git a/panda/src/gobj/qpgeomVertexDataType.I b/panda/src/gobj/qpgeomVertexDataType.I index 56e322476d..2cbaf3a0ba 100644 --- a/panda/src/gobj/qpgeomVertexDataType.I +++ b/panda/src/gobj/qpgeomVertexDataType.I @@ -164,6 +164,50 @@ overlaps_with(int start_byte, int num_bytes) const { _start + _total_bytes > start_byte); } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexDataType::is_bytewise_equivalent +// Access: Published +// Description: Returns true if the data store of this data type is +// exactly the same as that of the other, irrespective +// of name or start position within the record. +//////////////////////////////////////////////////////////////////// +INLINE bool qpGeomVertexDataType:: +is_bytewise_equivalent(const qpGeomVertexDataType &other) const { + // The _contents are relevant, because they specify such things as + // the difference between C_rgba and C_argb. + return (_num_components == other._num_components && + _numeric_type == other._numeric_type && + _contents == other._contents); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexDataType::is_packed_argb +// Access: Public +// Description: Returns true if this data type is the standard +// DirectX representation of 4-component color: C_argb, +// in NT_packed_8888, with 1 component (4 values). +//////////////////////////////////////////////////////////////////// +INLINE bool qpGeomVertexDataType:: +is_packed_argb() const { + return (_num_components == 1 && + _numeric_type == NT_packed_8888 && + _contents == C_argb); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexDataType::is_uint8_rgba +// Access: Public +// Description: Returns true if this data type is the standard +// OpenGL representation of 4-component color: C_rgba, +// in NT_uint8, with 4 components. +//////////////////////////////////////////////////////////////////// +INLINE bool qpGeomVertexDataType:: +is_uint8_rgba() const { + return (_num_components == 4 && + _numeric_type == NT_uint8 && + _contents == C_rgba); +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomVertexDataType::compare_to // Access: Public diff --git a/panda/src/gobj/qpgeomVertexDataType.cxx b/panda/src/gobj/qpgeomVertexDataType.cxx index 0cfd1ef365..e8b4d4e588 100644 --- a/panda/src/gobj/qpgeomVertexDataType.cxx +++ b/panda/src/gobj/qpgeomVertexDataType.cxx @@ -80,243 +80,3 @@ void qpGeomVertexDataType:: output(ostream &out) const { out << *get_name() << "(" << get_num_components() << ")"; } - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::copy_records -// Access: Published -// Description: Copies and converts from one data type to another. -// Copies the num_records records from the "from" -// buffer, encoded with from_type, to the "to" buffer, -// encoded with this current type, converting each one -// as necessary. -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -copy_records(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const { - // Temp for debugging. - static ConfigVariableBool do_copy_generic("copy-generic", false); - if (do_copy_generic) { - copy_generic(to, to_stride, from, from_stride, from_type, num_records); - return; - } - - if (get_numeric_type() == from_type->get_numeric_type() && - get_num_values() == from_type->get_num_values()) { - // An easy case. - copy_no_convert(to, to_stride, from, from_stride, from_type, num_records); - - } else if (get_numeric_type() == NT_uint8 && from_type->get_numeric_type() == NT_packed_8888 && - get_num_values() == from_type->get_num_values()) { - copy_argb_to_uint8(to, to_stride, from, from_stride, from_type, num_records); - } else if (get_numeric_type() == NT_packed_8888 && from_type->get_numeric_type() == NT_uint8 && - get_num_values() == from_type->get_num_values()) { - copy_uint8_to_argb(to, to_stride, from, from_stride, from_type, num_records); - } else { - copy_generic(to, to_stride, from, from_stride, from_type, num_records); - } -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::copy_no_convert -// Access: Private -// Description: Quickly copies data without the need to convert it. -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -copy_no_convert(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const { - if (to_stride == _total_bytes && from_stride == _total_bytes) { - // Fantastic! It's just a linear array of this one data type. - // Copy the whole thing all at once. - memcpy(to, from, num_records * _total_bytes); - - } else { - // Ok, it's interleaved in with other data. Copy them one record - // at a time. - while (num_records > 0) { - memcpy(to, from, _total_bytes); - to += to_stride; - from += from_stride; - num_records--; - } - } -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::copy_argb_to_uint8 -// Access: Private -// Description: Converts packed_argb to uint8-based r, g, b, a. -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -copy_argb_to_uint8(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const { - while (num_records > 0) { - PN_uint32 packed_argb = *(const PN_uint32 *)from; - to[0] = ((packed_argb >> 16) & 0xff); - to[1] = ((packed_argb >> 8) & 0xff); - to[2] = (packed_argb & 0xff); - to[3] = ((packed_argb >> 24) & 0xff); - - to += to_stride; - from += from_stride; - num_records--; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::copy_uint8_to_argb -// Access: Private -// Description: Converts uint8-based r, g, b, a to packed_argb. -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -copy_uint8_to_argb(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const { - while (num_records > 0) { - PN_uint32 packed_argb = ((from[3] << 24) | (from[0] << 16) | (from[1] << 8) | from[2]); - *(PN_uint32 *)to = packed_argb; - - to += to_stride; - from += from_stride; - num_records--; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::copy_generic -// Access: Private -// Description: A more general anything-to-anything copy (somewhat -// more expensive than the above). -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -copy_generic(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const { - int num_values_to_copy = min(get_num_values(), from_type->get_num_values()); - int num_values_to_fill = get_num_values() - num_values_to_copy; - - while (num_records > 0) { - int vi = 0; - while (vi < num_values_to_copy) { - float value = from_type->get_value(from, vi); - set_value(to, vi, value); - ++vi; - } - while (vi < num_values_to_fill) { - set_value(to, vi, 0.0f); - ++vi; - } - - to += to_stride; - from += from_stride; - num_records--; - } -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::get_value -// Access: Private -// Description: Returns the nth value of the data type, expressed as -// a float. -//////////////////////////////////////////////////////////////////// -float qpGeomVertexDataType:: -get_value(const unsigned char *data, int n) const { - switch (get_numeric_type()) { - case NT_uint16: - return (float)data[n]; - - case NT_uint8: - return (float)data[n] / 255.0f; - - case qpGeomVertexDataType::NT_packed_8888: - { - int element = n / 4; - const PN_uint32 *int_array = (const PN_uint32 *)data; - - PN_uint32 packed_argb = int_array[element]; - switch (n % 4) { - case 0: - return (float)((packed_argb >> 16) & 0xff) / 255.0f; - case 1: - return (float)((packed_argb >> 8) & 0xff) / 255.0f; - case 2: - return (float)(packed_argb & 0xff) / 255.0f; - case 3: - return (float)((packed_argb >> 24) & 0xff) / 255.0f; - } - } - break; - - case qpGeomVertexDataType::NT_float32: - { - const PN_float32 *float_array = (const PN_float32 *)data; - return float_array[n]; - } - } - - return 0.0f; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpGeomVertexDataType::set_value -// Access: Private -// Description: Modifies the nth value of the data type. -//////////////////////////////////////////////////////////////////// -void qpGeomVertexDataType:: -set_value(unsigned char *data, int n, float value) const { - switch (get_numeric_type()) { - case NT_uint16: - data[n] = (int)value; - break; - - case NT_uint8: - data[n] = (int)(value * 255.0f); - break; - - case qpGeomVertexDataType::NT_packed_8888: - { - int element = n / 4; - - union { - PN_uint32 _packed_argb; - struct { - unsigned char _a; - unsigned char _r; - unsigned char _g; - unsigned char _b; - } _argb; - } color; - - PN_uint32 *int_array = (PN_uint32 *)data; - color._packed_argb = int_array[element]; - switch (n % 4) { - case 0: - color._argb._r = (int)(value * 255.0f); - break; - case 1: - color._argb._g = (int)(value * 255.0f); - break; - case 2: - color._argb._b = (int)(value * 255.0f); - break; - case 3: - color._argb._a = (int)(value * 255.0f); - break; - } - int_array[element] = color._packed_argb; - } - break; - - case qpGeomVertexDataType::NT_float32: - PN_float32 *float_array = (PN_float32 *)data; - float_array[n] = value; - break; - } -} diff --git a/panda/src/gobj/qpgeomVertexDataType.h b/panda/src/gobj/qpgeomVertexDataType.h index 9445e3965e..1d0b3454c8 100644 --- a/panda/src/gobj/qpgeomVertexDataType.h +++ b/panda/src/gobj/qpgeomVertexDataType.h @@ -37,7 +37,7 @@ PUBLISHED: enum NumericType { NT_uint8, // An integer 0..255 NT_uint16, // An integer 0..65535 - NT_packed_8888, // DirectX style, four byte values packed in a dword + NT_packed_8888, // DirectX style, four byte values packed in a uint32 NT_float32, // A floating-point number }; @@ -69,42 +69,19 @@ PUBLISHED: INLINE int get_total_bytes() const; INLINE bool overlaps_with(int start_byte, int num_bytes) const; + INLINE bool is_bytewise_equivalent(const qpGeomVertexDataType &other) const; void output(ostream &out) const; public: + INLINE bool is_packed_argb() const; + INLINE bool is_uint8_rgba() const; + INLINE int compare_to(const qpGeomVertexDataType &other) const; INLINE bool operator == (const qpGeomVertexDataType &other) const; INLINE bool operator != (const qpGeomVertexDataType &other) const; INLINE bool operator < (const qpGeomVertexDataType &other) const; - void copy_records(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const; - -private: - void copy_no_convert(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const; - void copy_argb_to_uint8(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const; - void copy_uint8_to_argb(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const; - - void copy_generic(unsigned char *to, int to_stride, - const unsigned char *from, int from_stride, - const qpGeomVertexDataType *from_type, - int num_records) const; - - float get_value(const unsigned char *data, int n) const; - void set_value(unsigned char *data, int n, float value) const; - private: CPT(InternalName) _name; int _num_components;