diff --git a/panda/src/gobj/qpgeomVertexData.I b/panda/src/gobj/qpgeomVertexData.I index 5e0e0b0a66..fd2d7afe9a 100644 --- a/panda/src/gobj/qpgeomVertexData.I +++ b/panda/src/gobj/qpgeomVertexData.I @@ -160,6 +160,65 @@ get_modified() const { return cdata->_modified; } +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::pack_8888 +// Access: Public, Static +// Description: Packs four values in a DirectX-style NT_packed_8888 +// value. +//////////////////////////////////////////////////////////////////// +INLINE PN_uint32 qpGeomVertexData:: +pack_8888(unsigned int a, unsigned int b, + unsigned int c, unsigned int d) { + return (((a & 0xff) << 24) | + ((b & 0xff) << 16) | + ((c & 0xff) << 8) | + (d & 0xff)); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::unpack_8888_a +// Access: Public, Static +// Description: Returns the first packed value from a DirectX-style +// NT_packed_8888. +//////////////////////////////////////////////////////////////////// +INLINE unsigned int qpGeomVertexData:: +unpack_8888_a(PN_uint32 data) { + return (data >> 24) & 0xff; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::unpack_8888_b +// Access: Public, Static +// Description: Returns the second packed value from a DirectX-style +// NT_packed_8888. +//////////////////////////////////////////////////////////////////// +INLINE unsigned int qpGeomVertexData:: +unpack_8888_b(PN_uint32 data) { + return (data >> 16) & 0xff; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::unpack_8888_c +// Access: Public, Static +// Description: Returns the third packed value from a DirectX-style +// NT_packed_8888. +//////////////////////////////////////////////////////////////////// +INLINE unsigned int qpGeomVertexData:: +unpack_8888_c(PN_uint32 data) { + return (data >> 8) & 0xff; +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomVertexData::unpack_8888_d +// Access: Public, Static +// Description: Returns the fourth packed value from a DirectX-style +// NT_packed_8888. +//////////////////////////////////////////////////////////////////// +INLINE unsigned int qpGeomVertexData:: +unpack_8888_d(PN_uint32 data) { + return data & 0xff; +} + //////////////////////////////////////////////////////////////////// // Function: qpGeomVertexData::CData::Constructor // Access: Public diff --git a/panda/src/gobj/qpgeomVertexData.cxx b/panda/src/gobj/qpgeomVertexData.cxx index 3b99dd34de..068f3a12e6 100644 --- a/panda/src/gobj/qpgeomVertexData.cxx +++ b/panda/src/gobj/qpgeomVertexData.cxx @@ -723,18 +723,13 @@ packed_argb_to_uint8_rgba(unsigned char *to, int 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]; + PN_uint32 dword = *(const PN_uint32 *)from; + to[0] = unpack_8888_b(dword); + to[1] = unpack_8888_c(dword); + to[2] = unpack_8888_d(dword); + to[3] = unpack_8888_a(dword); to += to_stride; from += from_stride; @@ -758,18 +753,9 @@ uint8_rgba_to_packed_argb(unsigned char *to, int 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; + *(PN_uint32 *)to = pack_8888(from[3], from[0], from[1], from[2]); to += to_stride; from += from_stride; diff --git a/panda/src/gobj/qpgeomVertexData.h b/panda/src/gobj/qpgeomVertexData.h index 3acbd14ae7..71ac91b4ea 100644 --- a/panda/src/gobj/qpgeomVertexData.h +++ b/panda/src/gobj/qpgeomVertexData.h @@ -123,6 +123,13 @@ public: qpGeomVertexDataType::NumericType &numeric_type, int &start, int &stride) const; + static INLINE PN_uint32 pack_8888(unsigned int a, unsigned int b, + unsigned int c, unsigned int d); + static INLINE unsigned int unpack_8888_a(PN_uint32 data); + static INLINE unsigned int unpack_8888_b(PN_uint32 data); + static INLINE unsigned int unpack_8888_c(PN_uint32 data); + static INLINE unsigned int unpack_8888_d(PN_uint32 data); + private: static void bytewise_copy(unsigned char *to, int to_stride, const unsigned char *from, int from_stride, diff --git a/panda/src/gobj/qpgeomVertexReader.cxx b/panda/src/gobj/qpgeomVertexReader.cxx index ca712ca700..a0ed258e90 100644 --- a/panda/src/gobj/qpgeomVertexReader.cxx +++ b/panda/src/gobj/qpgeomVertexReader.cxx @@ -200,21 +200,20 @@ get_data1f(const unsigned char *pointer) { return maybe_scale_color(*pointer); case qpGeomVertexDataType::NT_uint16: - return *(PN_uint16 *)pointer; + return *(const PN_uint16 *)pointer; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - return maybe_scale_color(dword._b[1]); + return maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword)); } else { - return maybe_scale_color(dword._b[0]); + return maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword)); } } case qpGeomVertexDataType::NT_float32: - return *(PN_float32 *)pointer; + return *(const PN_float32 *)pointer; } return 0.0f; @@ -239,26 +238,27 @@ get_data2f(const unsigned char *pointer) { case qpGeomVertexDataType::NT_uint16: { - PN_uint16 *pi = (PN_uint16 *)pointer; + const PN_uint16 *pi = (const PN_uint16 *)pointer; _v2.set(pi[0], pi[1]); } return _v2; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - maybe_scale_color(dword._b[1], dword._b[2]); + maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword)); } else { - maybe_scale_color(dword._b[0], dword._b[1]); + maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword), + qpGeomVertexData::unpack_8888_b(dword)); } } return _v2; case qpGeomVertexDataType::NT_float32: { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v2.set(pi[0], pi[1]); } return _v2; @@ -295,26 +295,29 @@ get_data3f(const unsigned char *pointer) { case qpGeomVertexDataType::NT_uint16: { - PN_uint16 *pi = (PN_uint16 *)pointer; + const PN_uint16 *pi = (const PN_uint16 *)pointer; _v3.set(pi[0], pi[1], pi[2]); } return _v3; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - maybe_scale_color(dword._b[1], dword._b[2], dword._b[3]); + maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword)); } else { - maybe_scale_color(dword._b[0], dword._b[1], dword._b[2]); + maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword), + qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword)); } } return _v3; case qpGeomVertexDataType::NT_float32: { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v3.set(pi[0], pi[1], pi[2]); } return _v3; @@ -358,26 +361,31 @@ get_data4f(const unsigned char *pointer) { case qpGeomVertexDataType::NT_uint16: { - PN_uint16 *pi = (PN_uint16 *)pointer; + const PN_uint16 *pi = (const PN_uint16 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - maybe_scale_color(dword._b[1], dword._b[2], dword._b[3], dword._b[0]); + maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword), + qpGeomVertexData::unpack_8888_a(dword)); } else { - maybe_scale_color(dword._b[0], dword._b[1], dword._b[2], dword._b[3]); + maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword), + qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword)); } } return _v4; case qpGeomVertexDataType::NT_float32: { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; @@ -399,18 +407,17 @@ get_data1i(const unsigned char *pointer) { return *pointer; case qpGeomVertexDataType::NT_uint16: - return *(PN_uint16 *)pointer; + return *(const PN_uint16 *)pointer; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; - return dword._b[0]; + PN_uint32 dword = *(const PN_uint32 *)pointer; + return qpGeomVertexData::unpack_8888_a(dword); } break; case qpGeomVertexDataType::NT_float32: - return (int)*(PN_float32 *)pointer; + return (int)*(const PN_float32 *)pointer; } return 0; @@ -497,26 +504,31 @@ get_data4f(const unsigned char *pointer) { case qpGeomVertexDataType::NT_uint16: { - PN_uint16 *pi = (PN_uint16 *)pointer; + const PN_uint16 *pi = (const PN_uint16 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - maybe_scale_color(dword._b[1], dword._b[2], dword._b[3], dword._b[0]); + maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword), + qpGeomVertexData::unpack_8888_a(dword)); } else { - maybe_scale_color(dword._b[0], dword._b[1], dword._b[2], dword._b[3]); + maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword), + qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword)); } } return _v4; case qpGeomVertexDataType::NT_float32: { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; @@ -560,26 +572,31 @@ get_data4f(const unsigned char *pointer) { case qpGeomVertexDataType::NT_uint16: { - PN_uint16 *pi = (PN_uint16 *)pointer; + const PN_uint16 *pi = (const PN_uint16 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; + PN_uint32 dword = *(const PN_uint32 *)pointer; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - maybe_scale_color(dword._b[1], dword._b[2], dword._b[3], dword._b[0]); + maybe_scale_color(qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword), + qpGeomVertexData::unpack_8888_a(dword)); } else { - maybe_scale_color(dword._b[0], dword._b[1], dword._b[2], dword._b[3]); + maybe_scale_color(qpGeomVertexData::unpack_8888_a(dword), + qpGeomVertexData::unpack_8888_b(dword), + qpGeomVertexData::unpack_8888_c(dword), + qpGeomVertexData::unpack_8888_d(dword)); } } return _v4; case qpGeomVertexDataType::NT_float32: { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); } return _v4; @@ -596,7 +613,7 @@ get_data4f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase3f &qpGeomVertexReader::Reader_float32_3:: get_data3f(const unsigned char *pointer) { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v3.set(pi[0], pi[1], pi[2]); return _v3; } @@ -608,7 +625,7 @@ get_data3f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase2f &qpGeomVertexReader::Reader_point_float32_2:: get_data2f(const unsigned char *pointer) { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v2.set(pi[0], pi[1]); return _v2; } @@ -620,7 +637,7 @@ get_data2f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase3f &qpGeomVertexReader::Reader_point_float32_3:: get_data3f(const unsigned char *pointer) { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v3.set(pi[0], pi[1], pi[2]); return _v3; } @@ -632,7 +649,7 @@ get_data3f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase4f &qpGeomVertexReader::Reader_point_float32_4:: get_data4f(const unsigned char *pointer) { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); return _v4; } @@ -684,12 +701,11 @@ get_data4f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase4f &qpGeomVertexReader::Reader_argb_packed_8888:: get_data4f(const unsigned char *pointer) { - packed_8888 dword; - dword._i = *(PN_uint32 *)pointer; - _v4.set((float)dword._b[1] / 255.0f, - (float)dword._b[2] / 255.0f, - (float)dword._b[3] / 255.0f, - (float)dword._b[0] / 255.0f); + PN_uint32 dword = *(const PN_uint32 *)pointer; + _v4.set((float)qpGeomVertexData::unpack_8888_b(dword) / 255.0f, + (float)qpGeomVertexData::unpack_8888_c(dword) / 255.0f, + (float)qpGeomVertexData::unpack_8888_d(dword) / 255.0f, + (float)qpGeomVertexData::unpack_8888_a(dword) / 255.0f); return _v4; } @@ -714,7 +730,7 @@ get_data4f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// const LVecBase4f &qpGeomVertexReader::Reader_rgba_float32_4:: get_data4f(const unsigned char *pointer) { - PN_float32 *pi = (PN_float32 *)pointer; + const PN_float32 *pi = (const PN_float32 *)pointer; _v4.set(pi[0], pi[1], pi[2], pi[3]); return _v4; } @@ -736,5 +752,5 @@ get_data4f(const unsigned char *pointer) { //////////////////////////////////////////////////////////////////// int qpGeomVertexReader::Reader_uint16_1:: get_data1i(const unsigned char *pointer) { - return *(PN_uint16 *)pointer; + return *(const PN_uint16 *)pointer; } diff --git a/panda/src/gobj/qpgeomVertexReader.h b/panda/src/gobj/qpgeomVertexReader.h index d8015a6146..0de178e227 100644 --- a/panda/src/gobj/qpgeomVertexReader.h +++ b/panda/src/gobj/qpgeomVertexReader.h @@ -97,12 +97,6 @@ private: Reader *_reader; - // This union is handy for unpacking an NT_packed_8888 value. - typedef union { - unsigned char _b[4]; - PN_uint32 _i; - } packed_8888; - // This nested class provides the implementation for unpacking data // in a very general way, but also provides the hooks for // implementing the common, very direct code paths (for instance, diff --git a/panda/src/gobj/qpgeomVertexWriter.cxx b/panda/src/gobj/qpgeomVertexWriter.cxx index 4d960a7c18..dd01f9cee6 100644 --- a/panda/src/gobj/qpgeomVertexWriter.cxx +++ b/panda/src/gobj/qpgeomVertexWriter.cxx @@ -186,14 +186,12 @@ set_data1f(unsigned char *pointer, float data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = 0; + maybe_scale_color(data); if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[1] = maybe_scale_color(data); + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, 0, 0); } else { - dword._b[0] = maybe_scale_color(data); + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, 0, 0, 0); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -246,17 +244,12 @@ set_data2f(unsigned char *pointer, const LVecBase2f &data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; maybe_scale_color(data); - dword._i = 0; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[1] = _a; - dword._b[2] = _b; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, _b, 0); } else { - dword._b[0] = _a; - dword._b[1] = _b; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, 0, 0); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -316,20 +309,12 @@ set_data3f(unsigned char *pointer, const LVecBase3f &data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; maybe_scale_color(data); if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[0] = 0; - dword._b[1] = _a; - dword._b[2] = _b; - dword._b[3] = _c; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, _a, _b, _c); } else { - dword._b[0] = _a; - dword._b[1] = _b; - dword._b[2] = _c; - dword._b[3] = 0; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, _c, 0); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -392,20 +377,12 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; maybe_scale_color(data); if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[0] = _d; - dword._b[1] = _a; - dword._b[2] = _b; - dword._b[3] = _c; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_d, _a, _b, _c); } else { - dword._b[0] = _a; - dword._b[1] = _b; - dword._b[2] = _c; - dword._b[3] = _d; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, _c, _d); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -441,14 +418,11 @@ set_data1i(unsigned char *pointer, int data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; - dword._i = 0; if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[1] = data; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(0, data, 0, 0); } else { - dword._b[0] = data; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, data, 0, 0); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -542,20 +516,12 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) { case qpGeomVertexDataType::NT_packed_8888: { - packed_8888 dword; maybe_scale_color(data); if (_data_type->get_contents() == qpGeomVertexDataType::C_argb) { - dword._b[0] = _d; - dword._b[1] = _a; - dword._b[2] = _b; - dword._b[3] = _c; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_d, _a, _b, _c); } else { - dword._b[0] = _a; - dword._b[1] = _b; - dword._b[2] = _c; - dword._b[3] = _d; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888(_a, _b, _c, _d); } - *(PN_uint32 *)pointer = dword._i; } break; @@ -674,13 +640,11 @@ set_data4f(unsigned char *pointer, const LVecBase4f &data) { //////////////////////////////////////////////////////////////////// void qpGeomVertexWriter::Writer_argb_packed_8888:: set_data4f(unsigned char *pointer, const LVecBase4f &data) { - packed_8888 dword; - dword._b[0] = (unsigned int)(data[3] * 255.0f); - dword._b[1] = (unsigned int)(data[0] * 255.0f); - dword._b[2] = (unsigned int)(data[1] * 255.0f); - dword._b[3] = (unsigned int)(data[2] * 255.0f); - - *(PN_uint32 *)pointer = dword._i; + *(PN_uint32 *)pointer = qpGeomVertexData::pack_8888 + ((unsigned int)(data[3] * 255.0f), + (unsigned int)(data[0] * 255.0f), + (unsigned int)(data[1] * 255.0f), + (unsigned int)(data[2] * 255.0f)); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/gobj/qpgeomVertexWriter.h b/panda/src/gobj/qpgeomVertexWriter.h index 4b8a207776..75c8180566 100644 --- a/panda/src/gobj/qpgeomVertexWriter.h +++ b/panda/src/gobj/qpgeomVertexWriter.h @@ -124,12 +124,6 @@ private: Writer *_writer; - // This union is handy for packing an NT_packed_8888 value. - typedef union { - unsigned char _b[4]; - PN_uint32 _i; - } packed_8888; - // This nested class provides the implementation for unpacking data // in a very general way, but also provides the hooks for // implementing the common, very direct code paths (for instance,