Some minor refactors in octree code

* Moved static member functions of OctreeNode to .cpp file (and to
  private access because they are using only inside OctreeNode)
* Defined OctreeNodes type (alias for std::vector<OctreeNode*>)
* Changed m_pixelCount to size_t
* Added const modifier to some member functions
* Merged normalizeColor()+LeafColorToColor() -> rgbaColor()
* Refactor children() -> hasChildren() (because the function is only
  used to check if there are children in the node)
* Some initial values to member variables to remove constructors
  directly
* getModifications() -> modifications()
This commit is contained in:
David Capello 2021-05-09 17:36:17 -03:00
parent 8a22fe220c
commit 712b948a29
2 changed files with 108 additions and 103 deletions

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (c) 2020 Igara Studio S.A.
// Copyright (c) 2020-2021 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -17,6 +17,9 @@
namespace doc {
//////////////////////////////////////////////////////////////////////
// OctreeNode
void OctreeNode::addColor(color_t c, int level, OctreeNode* parent,
int paletteIndex, int levelDeep)
{
@ -38,12 +41,15 @@ void OctreeNode::fillOrphansNodes(const Palette* palette,
const int level)
{
for (int i=0; i<8; i++) {
if ((*m_children)[i].m_children)
(*m_children)[i].fillOrphansNodes(
OctreeNode& child = (*m_children)[i];
if (child.hasChildren()) {
child.fillOrphansNodes(
palette,
upstreamBranchColor + octetToBranchColor(i, level),
level + 1);
else if (!((*m_children)[i].isLeaf())) {
}
else if (!(child.isLeaf())) {
// Here the node IS NOT a Leaf and HAS NOT children
// So, we must assign palette index to the current node
// to fill the "map holes" (i.e "death tree branches")
@ -51,7 +57,7 @@ void OctreeNode::fillOrphansNodes(const Palette* palette,
// 0, 1, 2, or 3, we need to create branchs/Leaves until
// the desired minimum color MSB bits.
if (level < MIN_LEVEL_OCTREE_DEEP) {
(*m_children)[i].fillMostSignificantNodes(level);
child.fillMostSignificantNodes(level);
i--;
continue;
}
@ -67,7 +73,7 @@ void OctreeNode::fillOrphansNodes(const Palette* palette,
int indexMed = palette->findBestfit2(rgba_getr(branchColorMed),
rgba_getg(branchColorMed),
rgba_getb(branchColorMed));
(*m_children)[i].paletteIndex(indexMed);
child.paletteIndex(indexMed);
}
}
}
@ -77,8 +83,11 @@ void OctreeNode::fillMostSignificantNodes(int level)
if (level < MIN_LEVEL_OCTREE_DEEP) {
m_children.reset(new std::array<OctreeNode, 8>());
level++;
for (int i=0; i<8; i++)
(*m_children)[i].fillMostSignificantNodes(level);
for (int i=0; i<8; i++) {
OctreeNode& child = (*m_children)[i];
child.fillMostSignificantNodes(level);
}
}
}
@ -87,38 +96,46 @@ int OctreeNode::mapColor(int r, int g, int b, int level) const
int indexLevel = ( (b >> (7 - level)) & 1) * 4
+ ((g >> (7 - level)) & 1) * 2
+ ((r >> (7 - level)) & 1);
if ((*m_children)[indexLevel].m_children)
return (*m_children)[indexLevel].mapColor(r, g, b, level+1);
return (*m_children)[indexLevel].m_paletteIndex;
OctreeNode& child = (*m_children)[indexLevel];
if (child.hasChildren())
return child.mapColor(r, g, b, level+1);
else
return child.m_paletteIndex;
}
void OctreeNode::collectLeafNodes(std::vector<OctreeNode*>* leavesVector, int& paletteIndex)
void OctreeNode::collectLeafNodes(OctreeNodes& leavesVector, int& paletteIndex)
{
for (int i=0; i<8; i++) {
if ((*m_children)[i].isLeaf()) {
(*m_children)[i].paletteIndex(paletteIndex);
leavesVector->push_back(&(*m_children)[i]);
OctreeNode& child = (*m_children)[i];
if (child.isLeaf()) {
child.paletteIndex(paletteIndex);
leavesVector.push_back(&child);
paletteIndex++;
}
else if ((*m_children)[i].m_children)
(*m_children)[i].collectLeafNodes(leavesVector, paletteIndex);
else if (child.hasChildren()) {
child.collectLeafNodes(leavesVector, paletteIndex);
}
}
}
// removeLeaves(): remove leaves from a common parent
// auxParentVector: i/o addreess of an auxiliary parent leaf Vector from outside this function.
// rootLeavesVector: i/o address of the m_root->m_leavesVector
int OctreeNode::removeLeaves(std::vector<OctreeNode*>& auxParentVector,
std::vector<OctreeNode*>& rootLeavesVector,
int OctreeNode::removeLeaves(OctreeNodes& auxParentVector,
OctreeNodes& rootLeavesVector,
int octreeDeep)
{
// Apply to OctreeNode which has children which are leaf nodes
int result = 0;
for (int i=octreeDeep; i>=0; i--) {
if ((*m_children)[i].isLeaf()) {
m_leafColor.add((*m_children)[i].getLeafColor());
OctreeNode& child = (*m_children)[i];
if (child.isLeaf()) {
m_leafColor.add(child.leafColor());
result++;
if (rootLeavesVector[rootLeavesVector.size()-1] == &((*m_children)[i]))
if (rootLeavesVector[rootLeavesVector.size()-1] == &child)
rootLeavesVector.pop_back();
}
}
@ -126,22 +143,38 @@ int OctreeNode::removeLeaves(std::vector<OctreeNode*>& auxParentVector,
return result - 1;
}
OctreeMap::OctreeMap()
: m_palette(nullptr)
, m_modifications(0)
// static
int OctreeNode::getOctet(color_t c, int level)
{
int aux = c >> (7 - level);
int octet = aux & 1;
aux = aux >> (7);
octet += (aux & 2);
return octet + ((aux >> 7) & 4);
}
// static
color_t OctreeNode::octetToBranchColor(int octet, int level)
{
int auxR = (octet & 1) << (7 - level);
int auxG = (octet & 2) << (14 - level);
int auxB = (octet & 4) << (21 - level);
return auxR + auxG + auxB;
}
//////////////////////////////////////////////////////////////////////
// OctreeMap
bool OctreeMap::makePalette(Palette* palette,
const int colorCount,
const int levelDeep)
{
if (m_root.children()) {
if (m_root.hasChildren()) {
// We create paletteIndex to get a "global like" variable, in collectLeafNodes
// function, the purpose is having a incremental variable in the stack memory
// sharend between all recursive calls of collectLeafNodes.
int paletteIndex = 0;
m_root.collectLeafNodes(&m_leavesVector, paletteIndex);
m_root.collectLeafNodes(m_leavesVector, paletteIndex);
}
// If we can improve the octree accuracy, makePalette returns false, then
@ -151,7 +184,7 @@ bool OctreeMap::makePalette(Palette* palette,
return false;
std::vector<OctreeNode*> auxLeavesVector; // auxiliary collapsed node accumulator
OctreeNodes auxLeavesVector; // auxiliary collapsed node accumulator
bool keepReducingMap = true;
for (int level = levelDeep; level > -1; level--) {
@ -172,14 +205,14 @@ bool OctreeMap::makePalette(Palette* palette,
// Blend in pairs from the least pixelCount colors.
if (auxLeavesVector.size() <= 8 && colorCount < 8 && colorCount > 0) {
// Sort colors:
std::vector<OctreeNode*> sortedVector;
OctreeNodes sortedVector;
int auxVectorSize = auxLeavesVector.size();
for (int k=0; k < auxVectorSize; k++) {
int maximumCount = -1;
int maximumIndex = -1;
for (int j=0; j < auxLeavesVector.size(); j++) {
if (auxLeavesVector[j]->getLeafColor().pixelCount() > maximumCount) {
maximumCount = auxLeavesVector[j]->getLeafColor().pixelCount();
if (auxLeavesVector[j]->leafColor().pixelCount() > maximumCount) {
maximumCount = auxLeavesVector[j]->leafColor().pixelCount();
maximumIndex = j;
}
}
@ -194,8 +227,8 @@ bool OctreeMap::makePalette(Palette* palette,
m_leavesVector.push_back(sortedVector[k]);
break;
}
sortedVector[sortedVector.size()-2]->getLeafColor()
.add(sortedVector[sortedVector.size()-1]->getLeafColor());
sortedVector[sortedVector.size()-2]->leafColor()
.add(sortedVector[sortedVector.size()-1]->leafColor());
sortedVector.pop_back();
}
// End Blend colors:
@ -229,7 +262,8 @@ bool OctreeMap::makePalette(Palette* palette,
}
for (int i=0; i<leafCount; i++)
palette->setEntry(i+aux, m_leavesVector[i]->getLeafColor().normalizeColor().LeafColorToColor());
palette->setEntry(i+aux,
m_leavesVector[i]->leafColor().rgbaColor());
return true;
}
@ -260,7 +294,7 @@ void OctreeMap::feedWithImage(const Image* image,
int OctreeMap::mapColor(color_t rgba) const
{
if (m_root.children())
if (m_root.hasChildren())
return m_root.mapColor(rgba_getr(rgba),
rgba_getg(rgba),
rgba_getb(rgba), 0);

View File

@ -1,5 +1,5 @@
// Aseprite
// Copyright (c) 2020 Igara Studio S.A.
// Copyright (c) 2020-2021 Igara Studio S.A.
//
// This file is released under the terms of the MIT license.
// Read LICENSE.txt for more information.
@ -8,6 +8,7 @@
#define DOC_OCTREEMAP_H_INCLUDED
#pragma once
#include "doc/color.h"
#include "doc/image_impl.h"
#include "doc/palette.h"
#include "doc/rgbmap.h"
@ -18,6 +19,9 @@
namespace doc {
class OctreeNode;
using OctreeNodes = std::vector<OctreeNode*>;
class OctreeNode {
private:
class LeafColor {
@ -26,85 +30,52 @@ private:
m_r(0),
m_g(0),
m_b(0),
m_pixelCount(0)
{}
m_pixelCount(0) {
}
LeafColor(int r, int g, int b, int pixelCount) :
LeafColor(int r, int g, int b, size_t pixelCount) :
m_r((double)r),
m_g((double)g),
m_b((double)b),
m_pixelCount(pixelCount)
{}
m_pixelCount(pixelCount) {
}
void add(color_t c)
{
void add(color_t c) {
m_r += rgba_getr(c);
m_g += rgba_getg(c);
m_b += rgba_getb(c);
m_pixelCount++;
++m_pixelCount;
}
void add(LeafColor leafColor)
{
void add(LeafColor leafColor) {
m_r += leafColor.m_r;
m_g += leafColor.m_g;
m_b += leafColor.m_b;
m_pixelCount += leafColor.m_pixelCount;
}
LeafColor normalizeColor()
{
int auxR = (((int)m_r) % m_pixelCount > m_pixelCount / 2)? 1 : 0;
int auxG = (((int)m_g) % m_pixelCount > m_pixelCount / 2)? 1 : 0;
int auxB = (((int)m_b) % m_pixelCount > m_pixelCount / 2)? 1 : 0;
return LeafColor(m_r / m_pixelCount + auxR,
m_g / m_pixelCount + auxG,
m_b / m_pixelCount + auxB,
m_pixelCount);
color_t rgbaColor() const {
int auxR = (((int)m_r) % m_pixelCount > m_pixelCount / 2) ? 1: 0;
int auxG = (((int)m_g) % m_pixelCount > m_pixelCount / 2) ? 1: 0;
int auxB = (((int)m_b) % m_pixelCount > m_pixelCount / 2) ? 1: 0;
return rgba(int(m_r / m_pixelCount + auxR),
int(m_g / m_pixelCount + auxG),
int(m_b / m_pixelCount + auxB), 255);
}
color_t LeafColorToColor()
{
return 0xff000000 + (((int)m_b) << 16) + (((int)m_g) << 8) + (int)m_r;
}
int pixelCount() { return m_pixelCount; }
size_t pixelCount() const { return m_pixelCount; }
private:
double m_r;
double m_g;
double m_b;
int m_pixelCount;
size_t m_pixelCount;
};
public:
OctreeNode()
{
m_paletteIndex = 0;
m_children.reset(nullptr);
m_parent = nullptr;
}
static int getOctet(color_t c, int level)
{
int aux = c >> (7 - level);
int octet = aux & 1;
aux = aux >> (7);
octet += (aux & 2);
return octet + ((aux >> 7) & 4);
}
static color_t octetToBranchColor(int octet, int level)
{
int auxR = (octet & 1) << (7 - level);
int auxG = (octet & 2) << (14 - level);
int auxB = (octet & 4) << (21 - level);
return auxR + auxG + auxB;
}
OctreeNode* parent() const { return m_parent; }
std::array<OctreeNode, 8>* children() const { return m_children.get(); }
LeafColor getLeafColor() const { return m_leafColor; }
bool hasChildren() const { return m_children != nullptr; }
LeafColor leafColor() const { return m_leafColor; }
void addColor(color_t c, int level, OctreeNode* parent,
int paletteIndex = 0, int levelDeep = 7);
@ -117,31 +88,31 @@ public:
int mapColor(int r, int g, int b, int level) const;
void collectLeafNodes(std::vector<OctreeNode*>* leavesVector, int& paletteIndex);
void collectLeafNodes(OctreeNodes& leavesVector, int& paletteIndex);
// removeLeaves(): remove leaves from a common parent
// auxParentVector: i/o addreess of an auxiliary parent leaf Vector from outside.
// rootLeavesVector: i/o address of the m_root->m_leavesVector
int removeLeaves(std::vector<OctreeNode*>& auxParentVector,
std::vector<OctreeNode*>& rootLeavesVector,
int removeLeaves(OctreeNodes& auxParentVector,
OctreeNodes& rootLeavesVector,
int octreeDeep = 7);
private:
bool isLeaf() { return m_leafColor.pixelCount() > 0; }
void paletteIndex(int index) { m_paletteIndex = index; }
static int getOctet(color_t c, int level);
static color_t octetToBranchColor(int octet, int level);
LeafColor m_leafColor;
int m_paletteIndex;
int m_paletteIndex = 0;
std::unique_ptr<std::array<OctreeNode, 8>> m_children;
OctreeNode* m_parent;
OctreeNode* m_parent = nullptr;
};
class OctreeMap : public RgbMap {
public:
OctreeMap();
void addColor(color_t color, int levelDeep = 7)
{
void addColor(color_t color, int levelDeep = 7) {
m_root.addColor(color, 0, &m_root, 0, levelDeep);
}
@ -159,17 +130,17 @@ public:
void regenerateMap(const Palette* palette, const int maskIndex) override;
int mapColor(color_t rgba) const override;
int getModifications() const { return m_modifications; };
int moodifications() const { return m_modifications; };
private:
void fillOrphansNodes(const Palette* palette);
OctreeNode m_root;
std::vector<OctreeNode*> m_leavesVector;
const Palette* m_palette;
int m_modifications;
int m_maskIndex;
color_t m_maskColor;
OctreeNodes m_leavesVector;
const Palette* m_palette = nullptr;
int m_modifications = 0;
int m_maskIndex = 0;
color_t m_maskColor = 0;
};
} // namespace doc