Version 5.4.3.2, tag libreoffice-5.4.3.2
[LibreOffice.git] / vcl / source / gdi / octree.cxx
blob2abad5187f6e7950133f5934d396b05239966a22
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <limits.h>
22 #include <rtl/alloc.h>
23 #include <vcl/bitmapaccess.hxx>
25 #include "octree.hxx"
26 #include "impoctree.hxx"
28 static const sal_uInt8 pImplMask[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
30 ImpNodeCache::ImpNodeCache( const sal_uLong nInitSize ) :
31 pActNode( nullptr )
33 const sal_uLong nSize = nInitSize + 4;
35 for( sal_uLong i = 0; i < nSize; i++ )
37 OctreeNode* pNewNode = new NODE;
39 pNewNode->pNextInCache = pActNode;
40 pActNode = pNewNode;
44 ImpNodeCache::~ImpNodeCache()
46 while( pActNode )
48 OctreeNode* pNode = pActNode;
50 pActNode = pNode->pNextInCache;
51 delete pNode;
55 Octree::Octree(const BitmapReadAccess& rReadAcc, sal_uLong nColors)
56 : nMax(nColors)
57 , nLeafCount(0)
58 , nLevel(0)
59 , pTree(nullptr)
60 , pColor(nullptr)
61 , pAcc(&rReadAcc)
62 , nPalIndex(0)
64 pNodeCache = new ImpNodeCache( nColors );
65 memset( pReduce, 0, ( OCTREE_BITS + 1 ) * sizeof( NODE* ) );
67 if( !!*pAcc )
69 const long nWidth = pAcc->Width();
70 const long nHeight = pAcc->Height();
72 if( pAcc->HasPalette() )
74 for( long nY = 0; nY < nHeight; nY++ )
76 for( long nX = 0; nX < nWidth; nX++ )
78 pColor = &(BitmapColor&) pAcc->GetPaletteColor( pAcc->GetPixelIndex( nY, nX ) );
79 nLevel = 0;
80 ImplAdd( &pTree );
82 while( nLeafCount > nMax )
83 ImplReduce();
87 else
89 BitmapColor aColor;
91 pColor = &aColor;
93 for( long nY = 0; nY < nHeight; nY++ )
95 for( long nX = 0; nX < nWidth; nX++ )
97 aColor = pAcc->GetPixel( nY, nX );
98 nLevel = 0;
99 ImplAdd( &pTree );
101 while( nLeafCount > nMax )
102 ImplReduce();
109 Octree::~Octree()
111 ImplDeleteOctree( &pTree );
112 delete pNodeCache;
115 void Octree::ImplDeleteOctree( NODE** ppNode )
117 for (OctreeNode* i : (*ppNode)->pChild)
119 if ( i )
120 ImplDeleteOctree( &i );
123 pNodeCache->ImplReleaseNode( *ppNode );
124 *ppNode = nullptr;
127 void Octree::ImplAdd( NODE** ppNode )
129 // possibly generate new nodes
130 if( !*ppNode )
132 *ppNode = pNodeCache->ImplGetFreeNode();
133 (*ppNode)->bLeaf = ( OCTREE_BITS == nLevel );
135 if( (*ppNode)->bLeaf )
136 nLeafCount++;
137 else
139 (*ppNode)->pNext = pReduce[ nLevel ];
140 pReduce[ nLevel ] = *ppNode;
144 if( (*ppNode)->bLeaf )
146 (*ppNode)->nCount++;
147 (*ppNode)->nRed += pColor->GetRed();
148 (*ppNode)->nGreen += pColor->GetGreen();
149 (*ppNode)->nBlue += pColor->GetBlue();
151 else
153 const sal_uLong nShift = 7 - nLevel;
154 const sal_uInt8 cMask = pImplMask[ nLevel ];
155 const sal_uLong nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) |
156 ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) |
157 ( ( pColor->GetBlue() & cMask ) >> nShift );
159 nLevel++;
160 ImplAdd( &(*ppNode)->pChild[ nIndex ] );
164 void Octree::ImplReduce()
166 sal_uLong i;
167 NODE* pNode;
168 sal_uLong nRedSum = 0;
169 sal_uLong nGreenSum = 0;
170 sal_uLong nBlueSum = 0;
171 sal_uLong nChildren = 0;
173 for ( i = OCTREE_BITS - 1; i && !pReduce[i]; i-- ) {}
175 pNode = pReduce[ i ];
176 pReduce[ i ] = pNode->pNext;
178 for ( i = 0; i < 8; i++ )
180 if ( pNode->pChild[ i ] )
182 NODE* pChild = pNode->pChild[ i ];
184 nRedSum += pChild->nRed;
185 nGreenSum += pChild->nGreen;
186 nBlueSum += pChild->nBlue;
187 pNode->nCount += pChild->nCount;
189 pNodeCache->ImplReleaseNode( pNode->pChild[ i ] );
190 pNode->pChild[ i ] = nullptr;
191 nChildren++;
195 pNode->bLeaf = true;
196 pNode->nRed = nRedSum;
197 pNode->nGreen = nGreenSum;
198 pNode->nBlue = nBlueSum;
199 nLeafCount -= --nChildren;
202 void Octree::CreatePalette( NODE* pNode )
204 if( pNode->bLeaf )
206 pNode->nPalIndex = nPalIndex;
207 aPal[ nPalIndex++ ] = BitmapColor( (sal_uInt8) ( (double) pNode->nRed / pNode->nCount ),
208 (sal_uInt8) ( (double) pNode->nGreen / pNode->nCount ),
209 (sal_uInt8) ( (double) pNode->nBlue / pNode->nCount ) );
211 else for(OctreeNode* i : pNode->pChild)
212 if( i )
213 CreatePalette( i );
217 void Octree::GetPalIndex( NODE* pNode )
219 if ( pNode->bLeaf )
220 nPalIndex = pNode->nPalIndex;
221 else
223 const sal_uLong nShift = 7 - nLevel;
224 const sal_uInt8 cMask = pImplMask[ nLevel++ ];
225 const sal_uLong nIndex = ( ( ( pColor->GetRed() & cMask ) >> nShift ) << 2 ) |
226 ( ( ( pColor->GetGreen() & cMask ) >> nShift ) << 1 ) |
227 ( ( pColor->GetBlue() & cMask ) >> nShift );
229 GetPalIndex( pNode->pChild[ nIndex ] );
233 InverseColorMap::InverseColorMap( const BitmapPalette& rPal ) :
234 nBits( 8 - OCTREE_BITS )
236 const int nColorMax = 1 << OCTREE_BITS;
237 const unsigned long xsqr = 1 << ( nBits << 1 );
238 const unsigned long xsqr2 = xsqr << 1;
239 const int nColors = rPal.GetEntryCount();
240 const long x = 1 << nBits;
241 const long x2 = x >> 1;
242 sal_uLong r, g, b;
243 long rxx, gxx, bxx;
245 ImplCreateBuffers( nColorMax );
247 for( int nIndex = 0; nIndex < nColors; nIndex++ )
249 const BitmapColor& rColor = rPal[ (sal_uInt16) nIndex ];
250 const long cRed = rColor.GetRed();
251 const long cGreen = rColor.GetGreen();
252 const long cBlue = rColor.GetBlue();
254 long rdist = cRed - x2;
255 long gdist = cGreen - x2;
256 long bdist = cBlue - x2;
257 rdist = rdist*rdist + gdist*gdist + bdist*bdist;
259 const long crinc = ( xsqr - ( cRed << nBits ) ) << 1;
260 const long cginc = ( xsqr - ( cGreen << nBits ) ) << 1;
261 const long cbinc = ( xsqr - ( cBlue << nBits ) ) << 1;
263 sal_uLong* cdp = reinterpret_cast<sal_uLong*>(pBuffer);
264 sal_uInt8* crgbp = pMap;
266 for( r = 0, rxx = crinc; r < nColorMax; rdist += rxx, r++, rxx += xsqr2 )
268 for( g = 0, gdist = rdist, gxx = cginc; g < nColorMax; gdist += gxx, g++, gxx += xsqr2 )
270 for( b = 0, bdist = gdist, bxx = cbinc; b < nColorMax; bdist += bxx, b++, cdp++, crgbp++, bxx += xsqr2 )
271 if ( !nIndex || ( (long) *cdp ) > bdist )
273 *cdp = bdist;
274 *crgbp = (sal_uInt8) nIndex;
281 InverseColorMap::~InverseColorMap()
283 rtl_freeMemory( pBuffer );
284 rtl_freeMemory( pMap );
287 void InverseColorMap::ImplCreateBuffers( const sal_uLong nMax )
289 const sal_uLong nCount = nMax * nMax * nMax;
290 const sal_uLong nSize = nCount * sizeof( sal_uLong );
292 pMap = static_cast<sal_uInt8*>(rtl_allocateMemory( nCount ));
293 memset( pMap, 0x00, nCount );
295 pBuffer = static_cast<sal_uInt8*>(rtl_allocateMemory( nSize ));
296 memset( pBuffer, 0xff, nSize );
299 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */