From 712b948a29d33ea4a677ee18cfbc0b07b1343004 Mon Sep 17 00:00:00 2001 From: David Capello Date: Sun, 9 May 2021 17:36:17 -0300 Subject: [PATCH] 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) * 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() --- src/doc/octree_map.cpp | 104 +++++++++++++++++++++++++-------------- src/doc/octree_map.h | 107 +++++++++++++++-------------------------- 2 files changed, 108 insertions(+), 103 deletions(-) diff --git a/src/doc/octree_map.cpp b/src/doc/octree_map.cpp index 1bf03a1bd..d64d71bfa 100644 --- a/src/doc/octree_map.cpp +++ b/src/doc/octree_map.cpp @@ -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()); 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* 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& auxParentVector, - std::vector& 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& 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 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 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; isetEntry(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); diff --git a/src/doc/octree_map.h b/src/doc/octree_map.h index 9243cf913..ea0d8d9d6 100644 --- a/src/doc/octree_map.h +++ b/src/doc/octree_map.h @@ -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; + 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* 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* 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& auxParentVector, - std::vector& 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> 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 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