/*========================================================================= Program: Visualization Toolkit Module: vtkX3DExporterFIWriterHelper.h Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /** * @class vtkX3DExporterFIWriterHelper * */ #ifndef vtkX3DExporterFIWriterHelper_h #define vtkX3DExporterFIWriterHelper_h //#include "vtkX3DExporterFIByteWriter.h" #include "vtkZLibDataCompressor.h" #include #define EXPONENT_MASK_32 0x7f800000 #define MANTISSA_MASK_32 0x007fffff #ifndef max #define max(a, b) (((a) > (b)) ? (a) : (b)) #endif class vtkX3DExporterFIWriterHelper { public: union float_to_unsigned_int_to_bytes { float f; unsigned int ui; unsigned char ub[4]; // unsigned bytes }; template static inline void EncodeFloatFI(vtkX3DExporterFIByteWriter* writer, T* value, size_t size) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); // ITU C.19.3.4: If the alternative encoding-algorithm is present, // then the two bits '11' (discriminant) are appended writer->PutBits("11"); // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 7, writer->PutBits(7 - 1, 8); std::string bytes; char byte[4]; for (size_t i = 0; i < size; i++) { float_to_unsigned_int_to_bytes v; v.f = value[i]; // Avoid -0 if (v.ui == 0x80000000) { v.f = 0; } byte[0] = v.ub[3]; byte[1] = v.ub[2]; byte[2] = v.ub[1]; byte[3] = v.ub[0]; bytes.append(byte, 4); } EncodeNonEmptyByteString5(writer, bytes); } template static inline void EncodeIntegerFI(vtkX3DExporterFIByteWriter* writer, T* value, size_t size) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); // ITU C.19.3.4: If the alternative encoding-algorithm is present, // then the two bits '11' (discriminant) are appended writer->PutBits("11"); // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 4, writer->PutBits(4 - 1, 8); std::string bytes; for (size_t i = 0; i < size; i++) { int v = value[i]; int f = ReverseBytes(&v); char* p = reinterpret_cast(&f); bytes.append(p, 4); } EncodeNonEmptyByteString5(writer, bytes); } static inline void EncodeCharacterString3( vtkX3DExporterFIByteWriter* writer, const std::string& value) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); // ITU C.19.3.1 If the alternative utf-8 is present, then the two bits '00' // are appended to the bit stream. writer->PutBits("00"); // ITU C.19.4: The component bytes is encoded as described in C.23. EncodeNonEmptyByteString5(writer, value); } // ITU C.23: Encoding of the NonEmptyByteString starting // on the fifth bit of an byte static inline void EncodeNonEmptyByteString5( vtkX3DExporterFIByteWriter* writer, const std::string& value) { int length = static_cast(value.length()); if (length <= 8) { writer->PutBit(false); writer->PutBits(length - 1, 3); } else if (length <= 264) { writer->PutBits("1000"); writer->PutBits(length - 9, 8); } else { writer->PutBits("1100"); writer->PutBits(length - 265, 32); } writer->PutBytes(value.c_str(), length); } // ITU C.27: Encoding of integers in the range 1 to 2^20 // starting on the third bit of an byte static inline void EncodeInteger3(vtkX3DExporterFIByteWriter* writer, unsigned int value) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); if (value <= 32) // ITU C.27.2 { writer->PutBit(false); writer->PutBits(value - 1, 5); } else if (value <= 2080) // ITU C.27.3 { writer->PutBits("100"); writer->PutBits(value - 33, 11); } else if (value < 526368) // ITU C.27.4 { writer->PutBits("101"); writer->PutBits(value - 2081, 19); } else // ITU C.27.5 { writer->PutBits("1100000000"); writer->PutBits(value - 526369, 20); } } // ITU C.25: Encoding of integers in the range 1 to 2^20 // starting on the second bit of an byte static inline void EncodeInteger2(vtkX3DExporterFIByteWriter* writer, unsigned int value) { // We want to start at position 2 assert(writer->CurrentBytePos == 1); if (value <= 64) // ITU C.25.2 { writer->PutBits("0"); writer->PutBits(value - 1, 6); } else if (value <= 8256) // ITU C.25.3 { writer->PutBits("10"); writer->PutBits(value - 65, 13); } else // ITU C.25.4 { writer->PutBits("110"); writer->PutBits(value - 8257, 20); } } static inline void EncodeLineFeed(vtkX3DExporterFIByteWriter* writer) { static bool firstTime = true; writer->FillByte(); if (firstTime) { writer->PutBits("1001000000001010"); firstTime = false; } else { // cout << "Encode NOT the first time" << endl; writer->PutBits("10100000"); } } private: static int ReverseBytes(int* x) { /* break x apart, then put it back together backwards */ int part1 = (*x) & 0xFF; int part2 = ((*x) >> 8) & 0xFF; int part3 = ((*x) >> 16) & 0xFF; int part4 = ((*x) >> 24) & 0xFF; return (part1 << 24) | (part2 << 16) | (part3 << 8) | part4; } friend class X3DEncoderFunctions; }; class X3DEncoderFunctions { public: template static inline void EncodeIntegerDeltaZ(vtkX3DExporterFIByteWriter* writer, T* value, size_t size, vtkZLibDataCompressor* compressor, bool image = false) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); // ITU C.19.3.4: If the alternative encoding-algorithm is present, // then the two bits '11' (discriminant) are appended writer->PutBits("11"); // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33 writer->PutBits(34 - 1, 8); // compute delta char span = 0; size_t i = 0; int f; unsigned char* p; std::vector deltas; if (image) { span = 0; for (i = 0; i < size; i++) { int v = 1 + (value[i]); int* vp = reinterpret_cast(&v); f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp); p = reinterpret_cast(&f); deltas.push_back(p[0]); deltas.push_back(p[1]); deltas.push_back(p[2]); deltas.push_back(p[3]); } compressor->SetCompressionLevel(9); } else { for (i = 0; i < 20; i++) { if (value[i] == -1) { span = static_cast(i) + 1; break; } } if (!span) span = 4; for (i = 0; i < static_cast(span); i++) { int v = 1 + value[i]; int* vp = reinterpret_cast(&v); f = vtkX3DExporterFIWriterHelper::ReverseBytes(vp); p = reinterpret_cast(&f); deltas.push_back(p[0]); deltas.push_back(p[1]); deltas.push_back(p[2]); deltas.push_back(p[3]); } for (i = span; i < size; i++) { int v = 1 + (value[i] - value[i - span]); f = vtkX3DExporterFIWriterHelper::ReverseBytes(&v); p = reinterpret_cast(&f); deltas.push_back(p[0]); deltas.push_back(p[1]); deltas.push_back(p[2]); deltas.push_back(p[3]); } } size_t bufferSize = deltas.size() + static_cast(ceil(deltas.size() * 0.001)) + 12; unsigned char* buffer = new unsigned char[bufferSize]; size_t newSize = compressor->Compress(&deltas[0], static_cast(deltas.size()), buffer, static_cast(bufferSize)); std::string bytes; int size32 = static_cast(size); int size32_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&size32); char* s = reinterpret_cast(&size32_reversed); bytes.append(s, 4); bytes.append(&span, 1); for (i = 0; i < newSize; i++) { unsigned char c = buffer[i]; bytes += c; } delete[] buffer; vtkX3DExporterFIWriterHelper::EncodeNonEmptyByteString5(writer, bytes); if (image) { compressor->SetCompressionLevel(5); } } static inline void EncodeQuantizedzlibFloatArray(vtkX3DExporterFIByteWriter* writer, const double* value, size_t size, vtkZLibDataCompressor* compressor) { // We want to start at position 3 assert(writer->CurrentBytePos == 2); // ITU C.19.3.4: If the alternative encoding-algorithm is present, // then the two bits '11' (discriminant) are appended writer->PutBits("11"); // ITU 10.8.1: This encoding algorithm has a vocabulary table index of 33 writer->PutBits(34, 8); unsigned char* bytes = new unsigned char[size * 4]; unsigned char* bytepos = bytes; std::string bytesCompressed; size_t i; const double* vd = value; for (i = 0; i < size; i++) { union float_to_unsigned_int_to_bytes { float f; unsigned int ui; unsigned char ub[4]; // unsigned bytes }; float_to_unsigned_int_to_bytes v; v.f = (*vd) * 2.0; // Avoid -0 if (v.ui == 0x80000000) { v.f = 0.0f; } // vtkGenericWarningMacro(<< "value: " << v << " bytes: " << (int)s[0] << " " << (int)s[1] << // " " << (int)s[2] << " " << (int)s[3]); *bytepos++ = v.ub[3]; *bytepos++ = v.ub[2]; *bytepos++ = v.ub[1]; *bytepos++ = v.ub[0]; vd++; } // Compress the data size_t bufferSize = (size * 4) + static_cast(ceil((size * 4) * 0.001)) + 12; unsigned char* buffer = new unsigned char[bufferSize]; size_t newSize = compressor->Compress( bytes, static_cast(size * 4), buffer, static_cast(bufferSize)); char* s; // Put the number of bits for exponent bytesCompressed += static_cast(8); // Put the number of bits for mantissa bytesCompressed += static_cast(23); // Put the length int length = static_cast(size * 4); int length_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&length); s = reinterpret_cast(&length_reversed); bytesCompressed.append(s, 4); // Put the number of floats int numFloats = static_cast(size); int numFloats_reversed = vtkX3DExporterFIWriterHelper::ReverseBytes(&numFloats); s = reinterpret_cast(&numFloats_reversed); bytesCompressed.append(s, 4); for (i = 0; i < newSize; i++) { unsigned char c = buffer[i]; bytesCompressed += c; } vtkX3DExporterFIWriterHelper::EncodeNonEmptyByteString5(writer, bytesCompressed); delete[] buffer; delete[] bytes; } }; #endif // VTK-HeaderTest-Exclude: vtkX3DExporterFIWriterHelper.h