overte/libraries/octree/src/OctreePacketData.cpp
2014-01-28 11:18:37 -08:00

442 lines
13 KiB
C++

//
// OctreePacketData.cpp
// hifi
//
// Created by Brad Hefta-Gaub on 11/19/2013.
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#include <PerfStat.h>
#include "OctreePacketData.h"
bool OctreePacketData::_debug = false;
uint64_t OctreePacketData::_totalBytesOfOctalCodes = 0;
uint64_t OctreePacketData::_totalBytesOfBitMasks = 0;
uint64_t OctreePacketData::_totalBytesOfColor = 0;
uint64_t OctreePacketData::_totalBytesOfValues = 0;
uint64_t OctreePacketData::_totalBytesOfPositions = 0;
uint64_t OctreePacketData::_totalBytesOfRawData = 0;
OctreePacketData::OctreePacketData(bool enableCompression, int targetSize) {
changeSettings(enableCompression, targetSize); // does reset...
}
void OctreePacketData::changeSettings(bool enableCompression, int targetSize) {
_enableCompression = enableCompression;
_targetSize = std::min(MAX_OCTREE_UNCOMRESSED_PACKET_SIZE, targetSize);
reset();
}
void OctreePacketData::reset() {
_bytesInUse = 0;
_bytesAvailable = _targetSize;
_subTreeAt = 0;
_compressedBytes = 0;
_bytesInUseLastCheck = 0;
_dirty = false;
_bytesOfOctalCodes = 0;
_bytesOfBitMasks = 0;
_bytesOfColor = 0;
_bytesOfOctalCodesCurrentSubTree = 0;
}
OctreePacketData::~OctreePacketData() {
}
bool OctreePacketData::append(const unsigned char* data, int length) {
bool success = false;
if (length <= _bytesAvailable) {
memcpy(&_uncompressed[_bytesInUse], data, length);
_bytesInUse += length;
_bytesAvailable -= length;
success = true;
_dirty = true;
}
return success;
}
bool OctreePacketData::append(unsigned char byte) {
bool success = false;
if (_bytesAvailable > 0) {
_uncompressed[_bytesInUse] = byte;
_bytesInUse++;
_bytesAvailable--;
success = true;
_dirty = true;
}
return success;
}
bool OctreePacketData::updatePriorBitMask(int offset, unsigned char bitmask) {
bool success = false;
if (offset >= 0 && offset < _bytesInUse) {
_uncompressed[offset] = bitmask;
success = true;
_dirty = true;
}
return success;
}
bool OctreePacketData::updatePriorBytes(int offset, const unsigned char* replacementBytes, int length) {
bool success = false;
if (length >= 0 && offset >= 0 && ((offset + length) <= _bytesInUse)) {
memcpy(&_uncompressed[offset], replacementBytes, length); // copy new content
success = true;
_dirty = true;
}
return success;
}
bool OctreePacketData::startSubTree(const unsigned char* octcode) {
_bytesOfOctalCodesCurrentSubTree = _bytesOfOctalCodes;
bool success = false;
int possibleStartAt = _bytesInUse;
int length = 0;
if (octcode) {
length = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octcode));
success = append(octcode, length); // handles checking compression
} else {
// NULL case, means root node, which is 0
unsigned char byte = 0;
length = 1;
success = append(byte); // handles checking compression
}
if (success) {
_subTreeAt = possibleStartAt;
}
if (success) {
_bytesOfOctalCodes += length;
_totalBytesOfOctalCodes += length;
}
return success;
}
const unsigned char* OctreePacketData::getFinalizedData() {
if (!_enableCompression) {
return &_uncompressed[0];
}
if (_dirty) {
if (_debug) {
printf("getFinalizedData() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse);
}
compressContent();
}
return &_compressed[0];
}
int OctreePacketData::getFinalizedSize() {
if (!_enableCompression) {
return _bytesInUse;
}
if (_dirty) {
if (_debug) {
printf("getFinalizedSize() _compressedBytes=%d _bytesInUse=%d\n",_compressedBytes, _bytesInUse);
}
compressContent();
}
return _compressedBytes;
}
void OctreePacketData::endSubTree() {
_subTreeAt = _bytesInUse;
}
void OctreePacketData::discardSubTree() {
int bytesInSubTree = _bytesInUse - _subTreeAt;
_bytesInUse -= bytesInSubTree;
_bytesAvailable += bytesInSubTree;
_subTreeAt = _bytesInUse; // should be the same actually...
_dirty = true;
// rewind to start of this subtree, other items rewound by endLevel()
int reduceBytesOfOctalCodes = _bytesOfOctalCodes - _bytesOfOctalCodesCurrentSubTree;
_bytesOfOctalCodes = _bytesOfOctalCodesCurrentSubTree;
_totalBytesOfOctalCodes -= reduceBytesOfOctalCodes;
}
LevelDetails OctreePacketData::startLevel() {
LevelDetails key(_bytesInUse, _bytesOfOctalCodes, _bytesOfBitMasks, _bytesOfColor);
return key;
}
void OctreePacketData::discardLevel(LevelDetails key) {
int bytesInLevel = _bytesInUse - key._startIndex;
// reset statistics...
int reduceBytesOfOctalCodes = _bytesOfOctalCodes - key._bytesOfOctalCodes;
int reduceBytesOfBitMasks = _bytesOfBitMasks - key._bytesOfBitmasks;
int reduceBytesOfColor = _bytesOfColor - key._bytesOfColor;
_bytesOfOctalCodes = key._bytesOfOctalCodes;
_bytesOfBitMasks = key._bytesOfBitmasks;
_bytesOfColor = key._bytesOfColor;
_totalBytesOfOctalCodes -= reduceBytesOfOctalCodes;
_totalBytesOfBitMasks -= reduceBytesOfBitMasks;
_totalBytesOfColor -= reduceBytesOfColor;
if (_debug) {
printf("discardLevel() BEFORE _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n",
debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse);
}
_bytesInUse -= bytesInLevel;
_bytesAvailable += bytesInLevel;
_dirty = true;
if (_debug) {
printf("discardLevel() AFTER _dirty=%s bytesInLevel=%d _compressedBytes=%d _bytesInUse=%d\n",
debug::valueOf(_dirty), bytesInLevel, _compressedBytes, _bytesInUse);
}
}
bool OctreePacketData::endLevel(LevelDetails key) {
bool success = true;
return success;
}
bool OctreePacketData::appendBitMask(unsigned char bitmask) {
bool success = append(bitmask); // handles checking compression
if (success) {
_bytesOfBitMasks++;
_totalBytesOfBitMasks++;
}
return success;
}
bool OctreePacketData::appendColor(const nodeColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
bool OctreePacketData::appendColor(const rgbColor& color) {
return appendColor(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
bool OctreePacketData::appendColor(colorPart red, colorPart green, colorPart blue) {
// eventually we can make this use a dictionary...
bool success = false;
const int BYTES_PER_COLOR = 3;
if (_bytesAvailable > BYTES_PER_COLOR) {
// handles checking compression...
if (append(red)) {
if (append(green)) {
if (append(blue)) {
success = true;
}
}
}
}
if (success) {
_bytesOfColor += BYTES_PER_COLOR;
_totalBytesOfColor += BYTES_PER_COLOR;
}
return success;
}
bool OctreePacketData::appendValue(uint8_t value) {
bool success = append(value); // used unsigned char version
if (success) {
_bytesOfValues++;
_totalBytesOfValues++;
}
return success;
}
bool OctreePacketData::appendValue(uint16_t value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(uint32_t value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(uint64_t value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(float value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(const glm::vec3& value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(const glm::quat& value) {
const size_t VALUES_PER_QUAT = 4;
const size_t PACKED_QUAT_SIZE = sizeof(uint16_t) * VALUES_PER_QUAT;
unsigned char data[PACKED_QUAT_SIZE];
int length = packOrientationQuatToBytes(data, value);
bool success = append(data, length);
if (success) {
_bytesOfValues += length;
_totalBytesOfValues += length;
}
return success;
}
bool OctreePacketData::appendValue(bool value) {
bool success = append((uint8_t)value); // used unsigned char version
if (success) {
_bytesOfValues++;
_totalBytesOfValues++;
}
return success;
}
bool OctreePacketData::appendPosition(const glm::vec3& value) {
const unsigned char* data = (const unsigned char*)&value;
int length = sizeof(value);
bool success = append(data, length);
if (success) {
_bytesOfPositions += length;
_totalBytesOfPositions += length;
}
return success;
}
bool OctreePacketData::appendRawData(const unsigned char* data, int length) {
bool success = append(data, length);
if (success) {
_bytesOfRawData += length;
_totalBytesOfRawData += length;
}
return success;
}
uint64_t OctreePacketData::_compressContentTime = 0;
uint64_t OctreePacketData::_compressContentCalls = 0;
bool OctreePacketData::compressContent() {
PerformanceWarning warn(false, "OctreePacketData::compressContent()", false, &_compressContentTime, &_compressContentCalls);
// without compression, we always pass...
if (!_enableCompression) {
return true;
}
_bytesInUseLastCheck = _bytesInUse;
bool success = false;
const int MAX_COMPRESSION = 9;
// we only want to compress the data payload, not the message header
const uchar* uncompressedData = &_uncompressed[0];
int uncompressedSize = _bytesInUse;
QByteArray compressedData = qCompress(uncompressedData, uncompressedSize, MAX_COMPRESSION);
if (compressedData.size() < MAX_OCTREE_PACKET_DATA_SIZE) {
_compressedBytes = compressedData.size();
for (int i = 0; i < _compressedBytes; i++) {
_compressed[i] = compressedData[i];
}
_dirty = false;
success = true;
}
return success;
}
void OctreePacketData::loadFinalizedContent(const unsigned char* data, int length) {
reset();
if (data && length > 0) {
if (_enableCompression) {
QByteArray compressedData;
for (int i = 0; i < length; i++) {
compressedData[i] = data[i];
_compressed[i] = compressedData[i];
}
_compressedBytes = length;
QByteArray uncompressedData = qUncompress(compressedData);
if (uncompressedData.size() <= _bytesAvailable) {
_bytesInUse = uncompressedData.size();
_bytesAvailable -= uncompressedData.size();
for (int i = 0; i < _bytesInUse; i++) {
_uncompressed[i] = uncompressedData[i];
}
}
} else {
for (int i = 0; i < length; i++) {
_uncompressed[i] = _compressed[i] = data[i];
}
_bytesInUse = _compressedBytes = length;
}
} else {
if (_debug) {
printf("OctreePacketData::loadCompressedContent()... length = 0, nothing to do...\n");
}
}
}
void OctreePacketData::debugContent() {
printf("OctreePacketData::debugContent()... COMPRESSED DATA.... size=%d\n",_compressedBytes);
int perline=0;
for (int i = 0; i < _compressedBytes; i++) {
printf("%.2x ",_compressed[i]);
perline++;
if (perline >= 30) {
printf("\n");
perline=0;
}
}
printf("\n");
printf("OctreePacketData::debugContent()... UNCOMPRESSED DATA.... size=%d\n",_bytesInUse);
perline=0;
for (int i = 0; i < _bytesInUse; i++) {
printf("%.2x ",_uncompressed[i]);
perline++;
if (perline >= 30) {
printf("\n");
perline=0;
}
}
printf("\n");
}