mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 14:29:03 +02:00
Merge pull request #881 from Atlante45/png_import_cleanup
Png import cleanup
This commit is contained in:
commit
56f6b12fcd
3 changed files with 51 additions and 301 deletions
|
@ -1,242 +0,0 @@
|
||||||
//
|
|
||||||
// SquarePixelMap.cpp
|
|
||||||
// hifi
|
|
||||||
//
|
|
||||||
// Created by Tomáš Horáček on 6/25/13.
|
|
||||||
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "SquarePixelMap.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;
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
//
|
|
||||||
// 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__) */
|
|
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include <QRgb>
|
||||||
|
|
||||||
#include "CoverageMap.h"
|
#include "CoverageMap.h"
|
||||||
#include "GeometryUtil.h"
|
#include "GeometryUtil.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "SquarePixelMap.h"
|
|
||||||
#include "Tags.h"
|
#include "Tags.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
|
@ -1587,25 +1587,61 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) {
|
bool VoxelTree::readFromSquareARGB32Pixels(const char* filename) {
|
||||||
QImage pngImage = QImage(filename);
|
|
||||||
if (pngImage.height() != pngImage.width()) {
|
|
||||||
qDebug("ERROR: Bad PNG size: height != width.\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
emit importSize(1.0f, 1.0f, 1.0f);
|
emit importSize(1.0f, 1.0f, 1.0f);
|
||||||
emit importProgress(0);
|
emit importProgress(0);
|
||||||
|
|
||||||
const uint32_t* pixels;
|
int minAlpha = INT_MAX;
|
||||||
if (pngImage.format() == QImage::Format_ARGB32) {
|
|
||||||
pixels = reinterpret_cast<const uint32_t*>(pngImage.constBits());
|
QImage pngImage = QImage(filename);
|
||||||
} else {
|
|
||||||
QImage tmp = pngImage.convertToFormat(QImage::Format_ARGB32);
|
for (int x = 0; x < pngImage.width() * pngImage.height(); ++x) {
|
||||||
pixels = reinterpret_cast<const uint32_t*>(tmp.constBits());
|
minAlpha = std::min(qAlpha(pngImage.color(x)) , minAlpha);
|
||||||
}
|
}
|
||||||
|
|
||||||
SquarePixelMap pixelMap = SquarePixelMap(pixels, pngImage.height());
|
int maxSize = std::max(pngImage.width(), pngImage.height());
|
||||||
pixelMap.addVoxelsToVoxelTree(this);
|
|
||||||
|
int scale = 1;
|
||||||
|
while (maxSize > scale) {scale *= 2;}
|
||||||
|
float size = 1.0f / scale;
|
||||||
|
|
||||||
|
QRgb pixel;
|
||||||
|
int minNeighborhoodAlpha;
|
||||||
|
|
||||||
|
for (int i = 0; i < pngImage.width(); ++i) {
|
||||||
|
for (int j = 0; j < pngImage.height(); ++j) {
|
||||||
|
emit importProgress((100 * (i * pngImage.height() + j)) /
|
||||||
|
(pngImage.width() * pngImage.height()));
|
||||||
|
|
||||||
|
pixel = pngImage.pixel(i, j);
|
||||||
|
minNeighborhoodAlpha = qAlpha(pixel) - 1;
|
||||||
|
|
||||||
|
if (i != 0) {
|
||||||
|
minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i - 1, j)));
|
||||||
|
}
|
||||||
|
if (j != 0) {
|
||||||
|
minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j - 1)));
|
||||||
|
}
|
||||||
|
if (i < pngImage.width() - 1) {
|
||||||
|
minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i + 1, j)));
|
||||||
|
}
|
||||||
|
if (j < pngImage.height() - 1) {
|
||||||
|
minNeighborhoodAlpha = std::min(minNeighborhoodAlpha, qAlpha(pngImage.pixel(i, j + 1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
while (qAlpha(pixel) > minNeighborhoodAlpha) {
|
||||||
|
++minNeighborhoodAlpha;
|
||||||
|
createVoxel(i * size,
|
||||||
|
(minNeighborhoodAlpha - minAlpha) * size,
|
||||||
|
j * size,
|
||||||
|
size,
|
||||||
|
qRed(pixel),
|
||||||
|
qGreen(pixel),
|
||||||
|
qBlue(pixel),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit importProgress(100);
|
emit importProgress(100);
|
||||||
return true;
|
return true;
|
||||||
|
|
Loading…
Reference in a new issue