Merge pull request #607 from heracek/19385

Code Review for Job #19385
This commit is contained in:
ZappoMan 2013-07-02 14:16:13 -07:00
commit f36d7e7677
5 changed files with 322 additions and 5 deletions

View file

@ -30,6 +30,7 @@
#include <QCheckBox>
#include <QFormLayout>
#include <QGLWidget>
#include <QImage>
#include <QKeyEvent>
#include <QLineEdit>
#include <QMainWindow>
@ -1270,6 +1271,12 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
codeColorBuffer[bytesInCode + RED_INDEX ] = node->getColor()[RED_INDEX ];
codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX];
codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ];
// TODO: sendVoxelsOperation() is sending voxels too fast.
// This printf function accidently slowed down sending
// and hot-fixed the bug when importing
// large PNG models (256x256 px and more)
static unsigned int sendVoxelsOperationCalled = 0; printf("sending voxel #%u\n", ++sendVoxelsOperationCalled);
// if we have room don't have room in the buffer, then send the previously generated message first
if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) {
@ -1306,14 +1313,31 @@ void Application::exportVoxels() {
void Application::importVoxels() {
QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation);
QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), desktopLocation,
tr("Sparse Voxel Octree Files (*.svo)"));
tr("Sparse Voxel Octree Files, Square PNG (*.svo *.png)"));
QByteArray fileNameAscii = fileNameString.toAscii();
const char* fileName = fileNameAscii.data();
// Read the file into a tree
VoxelTree importVoxels;
importVoxels.readFromSVOFile(fileName);
if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) {
QImage pngImage = QImage(fileName);
if (pngImage.height() != pngImage.width()) {
printLog("ERROR: Bad PNG size: height != width.\n");
return;
}
const uint32_t* pixels;
if (pngImage.format() == QImage::Format_ARGB32) {
pixels = reinterpret_cast<const uint32_t*>(pngImage.constBits());
} else {
QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32);
pixels = reinterpret_cast<const uint32_t*>(tmp.constBits());
}
importVoxels.readFromSquareARGB32Pixels(pixels, pngImage.height());
} else {
importVoxels.readFromSVOFile(fileName);
}
VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
// Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to

View file

@ -0,0 +1,239 @@
//
// SquarePixelMap.cpp
// hifi
//
// Created by Tomáš Horáček on 6/25/13.
//
//
#include "SquarePixelMap.h"
#include <string.h>
#include <stdlib.h>
#define CHILD_COORD_X_IS_1 0x1
#define CHILD_COORD_Y_IS_1 0x2
#define ALPHA_CHANNEL_RANGE_FLOAT 256.f
#define ALPHA_CHANNEL_BIT_OFFSET 24
#define RED_CHANNEL_BIT_OFFSET 16
#define GREEN_CHANNEL_BIT_OFFSET 8
unsigned int numberOfBitsForSize(unsigned int size) {
if (size == 0) {
return 0;
}
size--;
unsigned int ans = 1;
while (size >>= 1) {
ans++;
}
return ans;
}
struct PixelQuadTreeCoordinates {
unsigned int x;
unsigned int y;
unsigned int size;
};
class PixelQuadTreeNode {
public:
PixelQuadTreeCoordinates _coord;
uint32_t _color; // undefined value for _allChildrenHasSameColor = false
bool _allChildrenHasSameColor;
uint8_t _minimumNeighbourhoodAplha;
// 0 x -> 1
// +---+---+
// y | 0 | 1 | <- child index
// | +---+---+
// v | 2 | 3 |
// +---+---+
// 1
PixelQuadTreeNode* _children[4];
PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap);
~PixelQuadTreeNode() {
for (int i = 0; i < 4; i++) {
delete _children[i];
}
}
private:
void updateChildCoordinates(int i, PixelQuadTreeCoordinates& childCoord) {
childCoord.x = _coord.x;
childCoord.y = _coord.y;
if (i & CHILD_COORD_X_IS_1) {
childCoord.x += childCoord.size;
}
if (i & CHILD_COORD_Y_IS_1) {
childCoord.y += childCoord.size;
}
}
bool hasAllChildrenSameColor() {
return false; //turn off import voxel grouping
for (int i = 1; i < 4; i++) {
if (!_children[i]->_allChildrenHasSameColor) {
return false;
}
}
uint32_t firstColor = _children[0]->_color;
for (int i = 1; i < 4; i++) {
if (firstColor != _children[i]->_color) {
return false;
}
}
return true;
}
};
PixelQuadTreeNode::PixelQuadTreeNode(PixelQuadTreeCoordinates coord, SquarePixelMap* pixelMap) : _coord(coord), _minimumNeighbourhoodAplha(-1) {
for (int i = 0; i < 4; i++) {
_children[i] = NULL;
}
if (_coord.size == 1) {
_color = pixelMap->getPixelAt(_coord.x, _coord.y);
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x + 1, _coord.y), _minimumNeighbourhoodAplha);
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x - 1, _coord.y), _minimumNeighbourhoodAplha);
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x, _coord.y + 1), _minimumNeighbourhoodAplha);
_minimumNeighbourhoodAplha = std::min<uint8_t>(pixelMap->getAlphaAt(_coord.x, _coord.y - 1), _minimumNeighbourhoodAplha);
_allChildrenHasSameColor = true;
} else {
PixelQuadTreeCoordinates childCoord = PixelQuadTreeCoordinates();
childCoord.size = _coord.size / 2;
for (int i = 0; i < 4; i++) {
this->updateChildCoordinates(i, childCoord);
if (childCoord.x < pixelMap->dimension() &&
childCoord.y < pixelMap->dimension()) {
_children[i] = new PixelQuadTreeNode(childCoord, pixelMap);
}
}
if (this->hasAllChildrenSameColor()) {
_allChildrenHasSameColor = true;
_color = _children[0]->_color;
_minimumNeighbourhoodAplha = _children[0]->_minimumNeighbourhoodAplha;
for (int i = 0; i < 4; i++) {
_minimumNeighbourhoodAplha = std::min<uint8_t>(_children[i]->_minimumNeighbourhoodAplha, _minimumNeighbourhoodAplha);
delete _children[i];
_children[i] = NULL;
}
} else {
_allChildrenHasSameColor = false;
}
}
}
SquarePixelMap::SquarePixelMap(const uint32_t* pixels, int dimension) : _rootPixelQuadTreeNode(NULL) {
_data = new SquarePixelMapData();
_data->dimension = dimension;
_data->reference_counter = 1;
size_t pixels_size = dimension * dimension;
_data->pixels = new uint32_t[pixels_size];
memcpy((void*)_data->pixels, (void*)pixels, sizeof(uint32_t) * pixels_size);
}
SquarePixelMap::SquarePixelMap(const SquarePixelMap& other) {
this->_data = other._data;
this->_data->reference_counter++;
}
SquarePixelMap::~SquarePixelMap() {
delete _rootPixelQuadTreeNode;
if (--_data->reference_counter == 0) {
delete _data->pixels;
delete _data;
}
}
void SquarePixelMap::addVoxelsToVoxelTree(VoxelTree* voxelTree) {
this->generateRootPixelQuadTreeNode();
this->createVoxelsFromPixelQuadTreeToVoxelTree(_rootPixelQuadTreeNode, voxelTree);
}
int SquarePixelMap::dimension() {
return _data->dimension;
}
uint32_t SquarePixelMap::getPixelAt(unsigned int x, unsigned int y) {
return _data->pixels[x + y * _data->dimension];
}
uint8_t SquarePixelMap::getAlphaAt(int x, int y) {
int max_coord = this->dimension() - 1;
if (x < 0 || y < 0 || x > max_coord || y > max_coord) {
return -1;
}
return this->getPixelAt(x, y) >> ALPHA_CHANNEL_BIT_OFFSET;
}
void SquarePixelMap::generateRootPixelQuadTreeNode() {
delete _rootPixelQuadTreeNode;
PixelQuadTreeCoordinates rootNodeCoord = PixelQuadTreeCoordinates();
rootNodeCoord.size = 1 << numberOfBitsForSize(_data->dimension);
rootNodeCoord.x = rootNodeCoord.y = 0;
_rootPixelQuadTreeNode = new PixelQuadTreeNode(rootNodeCoord, this);
}
void SquarePixelMap::createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree) {
if (pixelQuadTreeNode->_allChildrenHasSameColor) {
VoxelDetail voxel = this->getVoxelDetail(pixelQuadTreeNode);
unsigned char minimumNeighbourhoodAplha = std::max<int>(0, pixelQuadTreeNode->_minimumNeighbourhoodAplha - 1);
float minimumNeighbourhoodY = voxel.s * (floor(minimumNeighbourhoodAplha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5);
do {
voxelTree->createVoxel(voxel.x, voxel.y, voxel.z, voxel.s, voxel.red, voxel.green, voxel.blue, true);
} while ((voxel.y -= voxel.s) > minimumNeighbourhoodY);
} else {
for (int i = 0; i < 4; i++) {
PixelQuadTreeNode* child = pixelQuadTreeNode->_children[i];
if (child) {
this->createVoxelsFromPixelQuadTreeToVoxelTree(child, voxelTree);
}
}
}
}
VoxelDetail SquarePixelMap::getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode) {
VoxelDetail voxel = VoxelDetail();
uint32_t color = pixelQuadTreeNode->_color;
unsigned char alpha = std::max<int>(0, (color >> ALPHA_CHANNEL_BIT_OFFSET) - 1);
voxel.red = color >> RED_CHANNEL_BIT_OFFSET;
voxel.green = color >> GREEN_CHANNEL_BIT_OFFSET;
voxel.blue = color;
float rootSize = _rootPixelQuadTreeNode->_coord.size;
voxel.s = pixelQuadTreeNode->_coord.size / rootSize;
voxel.y = voxel.s * (floor(alpha / (ALPHA_CHANNEL_RANGE_FLOAT * voxel.s)) + 0.5);
voxel.x = pixelQuadTreeNode->_coord.x / rootSize + voxel.s / 2;
voxel.z = pixelQuadTreeNode->_coord.y / rootSize + voxel.s / 2;
return voxel;
}

View file

@ -0,0 +1,44 @@
//
// SquarePixelMap.h
// hifi
//
// Created by Tomáš Horáček on 6/25/13.
//
//
#ifndef __hifi__SquarePixelMap__
#define __hifi__SquarePixelMap__
#include <stdint.h>
#include "VoxelTree.h"
#include "SharedUtil.h"
class PixelQuadTreeNode;
struct SquarePixelMapData {
const uint32_t* pixels;
int dimension;
int reference_counter;
};
class SquarePixelMap {
public:
SquarePixelMap(const uint32_t* pixels, int dimension);
SquarePixelMap(const SquarePixelMap& other);
~SquarePixelMap();
void addVoxelsToVoxelTree(VoxelTree* voxelTree);
int dimension();
uint32_t getPixelAt(unsigned int x, unsigned int y);
uint8_t getAlphaAt(int x, int y);
private:
SquarePixelMapData* _data;
PixelQuadTreeNode* _rootPixelQuadTreeNode;
void generateRootPixelQuadTreeNode();
void createVoxelsFromPixelQuadTreeToVoxelTree(PixelQuadTreeNode* pixelQuadTreeNode, VoxelTree* voxelTree);
VoxelDetail getVoxelDetail(PixelQuadTreeNode* pixelQuadTreeNode);
};
#endif /* defined(__hifi__SquarePixelMap__) */

View file

@ -23,6 +23,8 @@
#include <fstream> // to load voxels from file
#include "VoxelConstants.h"
#include "CoverageMap.h"
#include "SquarePixelMap.h"
#include <glm/gtc/noise.hpp>
@ -1447,6 +1449,12 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
return false;
}
bool VoxelTree::readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension) {
SquarePixelMap pixelMap = SquarePixelMap(pixels, dimension);
pixelMap.addVoxelsToVoxelTree(this);
return true;
}
void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const {
std::ofstream file(fileName, std::ios::out|std::ios::binary);

View file

@ -133,6 +133,8 @@ public:
// these will read/write files that match the wireformat, excluding the 'V' leading
void writeToSVOFile(const char* filename, VoxelNode* node = NULL) const;
bool readFromSVOFile(const char* filename);
// reads voxels from square image with alpha as a Y-axis
bool readFromSquareARGB32Pixels(const uint32_t* pixels, int dimension);
unsigned long getVoxelCount();