blob: 0028fd296c49db09f9c8a6d5a63e399cc6a6507e [file] [log] [blame]
/*
* Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* FUNCTION
* mlib_ImageColorTrue2Index - convert a true color image to an indexed
* color image
*
* SYNOPSIS
* mlib_status mlib_ImageColorTrue2Index(mlib_image *dst,
* const mlib_image *src,
* const void *colormap)
*
* ARGUMENTS
* colormap Internal data structure for inverse color mapping.
* dst Pointer to destination image.
* src Pointer to source image.
*
* DESCRIPTION
* Convert a true color image to a pseudo color image with the method
* of finding the nearest matched lut entry for each pixel.
*
* The src can be an MLIB_BYTE or MLIB_SHORT image with 3 or 4 channels.
* The dst must be a 1-channel MLIB_BYTE or MLIB_SHORT image.
*
* The lut might have either 3 or 4 channels. The type of the lut can be
* one of the following:
* MLIB_BYTE in, MLIB_BYTE out (i.e., BYTE-to-BYTE)
* MLIB_BYTE in, MLIB_SHORT out (i.e., BYTE-to-SHORT)
* MLIB_SHORT in, MLIB_SHORT out (i.e., SHORT-to-SHORT)
* MLIB_SHORT in, MLIB_BYTE out (i.e., SHORT-to-BYTE)
*
* The src image and the lut must have same number of channels.
*/
#include "mlib_image.h"
#include "mlib_ImageColormap.h"
#include "mlib_ImageCheck.h"
/***************************************************************/
/*#define USE_VIS_CODE*/
#ifdef USE_VIS_CODE
#include "vis_proto.h"
#define VIS_ALIGNADDR(X, Y) vis_alignaddr((void *)(X), (Y))
#endif
/***************************************************************/
#define LUT_BYTE_COLORS_3CHANNELS 1000
#define LUT_BYTE_COLORS_4CHANNELS 3000
#define LUT_SHORT_COLORS_3CHANNELS 1000
#define LUT_SHORT_COLORS_4CHANNELS 1000
/***************************************************************/
#define MAIN_COLORTRUE2INDEX_LOOP( FROM_TYPE, TO_TYPE, NCHANNELS ) \
for( y = 0; y < height; y++ ) \
{ \
mlib_ImageColorTrue2IndexLine_##FROM_TYPE##_##TO_TYPE##_##NCHANNELS( \
sdata, ddata, width, colormap ); \
\
sdata += sstride; \
ddata += dstride; \
}
/***************************************************************/
#define COLOR_CUBE_U8_3_SEARCH( TABLE_POINTER_TYPE, SHIFT, STEP ) \
{ \
const mlib_u8 *c0, *c1, *c2; \
TABLE_POINTER_TYPE *table = s->table; \
mlib_s32 bits = s->bits; \
mlib_s32 nbits = 8 - bits; \
mlib_s32 mask = ~( ( 1 << nbits ) - 1 ); \
mlib_s32 j; \
\
c0 = src + SHIFT; \
c1 = src + 1 + SHIFT; \
c2 = src + 2 + SHIFT; \
\
switch( bits ) \
{ \
case 1: \
case 2: \
{ \
mlib_s32 bits0 = 8 - bits; \
mlib_s32 bits1 = bits0 - bits; \
mlib_s32 bits2 = bits1 - bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) >> bits2 ) | \
( ( *c1 & mask ) >> bits1 ) | \
( ( *c2 & mask ) >> bits0 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 3: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 1 ) | \
( ( *c1 & mask ) >> 2 ) | \
( ( *c2 & mask ) >> 5 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 4: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 4 ) | \
( *c1 & mask ) | \
( ( *c2 & mask ) >> 4 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 5: \
case 6: \
case 7: \
{ \
mlib_s32 bits0 = 8 - bits; \
mlib_s32 bits1 = bits * 2 - 8; \
mlib_s32 bits2 = bits1 + bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << bits2 ) | \
( ( *c1 & mask ) << bits1 ) | \
( ( *c2 & mask ) >> bits0 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 8: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 16 ) | \
( ( *c1 & mask ) << 8 ) | \
( *c2 & mask ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
} \
}
/***************************************************************/
#define COLOR_CUBE_U8_4_SEARCH( TABLE_TYPE ) \
{ \
const mlib_u8 *c0, *c1, *c2, *c3; \
TABLE_TYPE *table = s->table; \
mlib_s32 bits = s->bits; \
mlib_s32 nbits = 8 - bits; \
mlib_s32 mask = ~( ( 1 << nbits ) - 1 ); \
mlib_s32 j; \
\
c0 = src; \
c1 = src + 1; \
c2 = src + 2; \
c3 = src + 3; \
\
switch( bits ) \
{ \
case 1: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) >> 4 ) | \
( ( *c1 & mask ) >> 5 ) | \
( ( *c2 & mask ) >> 6 ) | \
( ( *c3 & mask ) >> 7 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 2: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( *c0 & mask ) | \
( ( *c1 & mask ) >> 2 ) | \
( ( *c2 & mask ) >> 4 ) | \
( ( *c3 & mask ) >> 6 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 3: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 4 ) | \
( ( *c1 & mask ) << 1 ) | \
( ( *c2 & mask ) >> 2 ) | \
( ( *c3 & mask ) >> 5 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 4: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 8 ) | \
( ( *c1 & mask ) << 4 ) | \
( *c2 & mask ) | \
( ( *c3 & mask ) >> 4 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 5: \
case 6: \
{ \
mlib_s32 bits3 = bits * 4 - 8; \
mlib_s32 bits2 = bits3 - bits; \
mlib_s32 bits1 = bits2 - bits; \
mlib_s32 bits0 = 8 - bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << bits3 ) | \
( ( *c1 & mask ) << bits2 ) | \
( ( *c2 & mask ) << bits1 ) | \
( ( *c3 & mask ) >> bits0 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 7: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 20 ) | \
( ( *c1 & mask ) << 13 ) | \
( ( *c2 & mask ) << 6 ) | \
( ( *c3 & mask ) >> 1 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 8: /* will never be called */ \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 & mask ) << 24 ) | \
( ( *c1 & mask ) << 16 ) | \
( ( *c2 & mask ) << 8 ) | \
( *c3 & mask ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
} \
}
/***************************************************************/
#define COLOR_CUBE_S16_3_SEARCH( TABLE_TYPE, SHIFT, STEP ) \
{ \
const mlib_s16 *c0, *c1, *c2; \
mlib_s32 bits = s->bits; \
mlib_s32 nbits = 16 - bits; \
mlib_s32 mask = ~( ( 1 << nbits ) - 1 ); \
TABLE_TYPE *table = s->table; \
mlib_s32 j; \
\
c0 = src + SHIFT; \
c1 = src + 1 + SHIFT; \
c2 = src + 2 + SHIFT; \
\
switch( bits ) \
{ \
case 1: \
case 2: \
case 3: \
case 4: \
case 5: \
{ \
mlib_s32 bits0 = 16 - bits; \
mlib_s32 bits1 = bits0 - bits; \
mlib_s32 bits2 = bits1 - bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) >> bits2 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) >> bits1 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> bits0 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 6: \
case 7: \
{ \
mlib_s32 bits0 = 16 - bits; \
mlib_s32 bits1 = bits0 - bits; \
mlib_s32 bits2 = bits * 3 - 16; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << bits2 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) >> bits1 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> bits0 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 8: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << 8 ) | \
( ( *c1 - MLIB_S16_MIN ) & mask ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> 8 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
case 9: \
case 10: \
{ \
mlib_s32 bits0 = 16 - bits; \
mlib_s32 bits1 = 2 * bits - 16; \
mlib_s32 bits2 = bits1 + bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << bits2 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) << bits1 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> bits0 ) ]; \
\
c0 += STEP; \
c1 += STEP; \
c2 += STEP; \
} \
break; \
} \
/* Other cases may not be considered as the table size will be more \
than 2^32 */ \
} \
}
/***************************************************************/
#define COLOR_CUBE_S16_4_SEARCH( TABLE_TYPE ) \
{ \
const mlib_s16 *c0, *c1, *c2, *c3; \
TABLE_TYPE *table = s->table; \
mlib_s32 bits = s->bits; \
mlib_s32 nbits = 16 - bits; \
mlib_s32 mask = ~( ( 1 << nbits ) - 1 ); \
mlib_s32 j; \
\
c0 = src; \
c1 = src + 1; \
c2 = src + 2; \
c3 = src + 3; \
\
switch( bits ) \
{ \
case 1: \
case 2: \
case 3: \
{ \
mlib_s32 bits0 = 16 - bits; \
mlib_s32 bits1 = bits0 - bits; \
mlib_s32 bits2 = bits1 - bits; \
mlib_s32 bits3 = bits2 - bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) >> bits3 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) >> bits2 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> bits1 ) | \
( ( ( *c3 - MLIB_S16_MIN ) & mask ) >> bits0 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 4: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( *c0 - MLIB_S16_MIN ) & mask ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) >> 4 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> 8 ) | \
( ( ( *c3 - MLIB_S16_MIN ) & mask ) >> 12 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 5: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << 4 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) >> 1 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> 6 ) | \
( ( ( *c3 - MLIB_S16_MIN ) & mask ) >> 11 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 6: \
case 7: \
{ \
mlib_s32 bits0 = 16 - bits; \
mlib_s32 bits1 = bits0 - bits; \
mlib_s32 bits3 = bits * 4 - 16; \
mlib_s32 bits2 = bits3 - bits; \
\
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << bits3 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) << bits2 ) | \
( ( ( *c2 - MLIB_S16_MIN ) & mask ) >> bits1 ) | \
( ( ( *c3 - MLIB_S16_MIN ) & mask ) >> bits0 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
case 8: \
{ \
for( j = 0; j < length; j++ ) \
{ \
dst[ j ] = table[ ( ( ( *c0 - MLIB_S16_MIN ) & mask ) << 16 ) | \
( ( ( *c1 - MLIB_S16_MIN ) & mask ) << 8 ) | \
( ( *c2 - MLIB_S16_MIN ) & mask ) | \
( ( ( *c3 - MLIB_S16_MIN ) & mask ) >> 8 ) ]; \
\
c0 += 4; \
c1 += 4; \
c2 += 4; \
c3 += 4; \
} \
break; \
} \
/* Other cases may not be considered as the table size will be more \
than 2^32 */ \
} \
}
/***************************************************************/
#define BINARY_TREE_SEARCH_RIGHT( POSITION, COLOR_MAX, SHIFT ) \
{ \
if( ( distance >= ( ( ( position[ POSITION ] + current_size - \
c[ POSITION ] ) * ( position[ POSITION ] + current_size - \
c[ POSITION ] ) ) >> SHIFT ) ) && \
( position[ POSITION ] + current_size != COLOR_MAX ) ) \
continue_up = 1; \
}
/***************************************************************/
#define BINARY_TREE_EXPLORE_RIGHT_3( POSITION, COLOR_MAX, IMAGE_TYPE, \
FIRST_NEIBOUR, SECOND_NEIBOUR, SUBSTRACTION, SHIFT ) \
{ \
if( distance >= ( ( ( position[ POSITION ] + current_size - \
c[ POSITION ] ) * ( position[ POSITION ] + \
current_size - c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance < ( ( ( COLOR_MAX - c[ POSITION ] ) * \
( COLOR_MAX - c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance < ( ( ( position[ POSITION ] + \
current_size * 2 - c[ POSITION ] ) * \
( position[ POSITION ] + current_size * 2 - \
c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
/* Check only a part of quadrant */ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_corner += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_left_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] + current_size, pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_corner += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], p ); \
} \
} \
else /* Cell is on the edge of the space */ \
{ \
if( position[ POSITION ] + current_size * 2 == \
COLOR_MAX ) \
{ \
/* Check only a part of quadrant */ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_corner += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_left_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] + current_size, \
pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_corner += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], p ); \
} \
} \
} \
}
/***************************************************************/
#define BINARY_TREE_EXPLORE_RIGHT_4( POSITION, COLOR_MAX, IMAGE_TYPE, \
FIRST_NEIBOUR, SECOND_NEIBOUR, THIRD_NEIBOUR, SUBSTRACTION, SHIFT ) \
{ \
if( distance >= ( ( ( position[ POSITION ] + current_size - \
c[ POSITION ] ) * ( position[ POSITION ] + \
current_size - c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance < ( ( ( COLOR_MAX - c[ POSITION ] ) * \
( COLOR_MAX - c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance < ( ( ( position[ POSITION ] + \
current_size * 2 - c[ POSITION ] ) * \
( position[ POSITION ] + current_size * 2 - \
c[ POSITION ] ) ) >> SHIFT ) ) \
{ \
/* Check only a part of quadrant */ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_neibours[ THIRD_NEIBOUR ] += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_left_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] + current_size, pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_neibours[ THIRD_NEIBOUR ] += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
} \
} \
else /* Cell is on the edge of the space */ \
{ \
if( position[ POSITION ] + current_size * 2 == \
COLOR_MAX ) \
{ \
/* Check only a part of quadrant */ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_neibours[ THIRD_NEIBOUR ] += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_left_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] + current_size, \
pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_neibours[ THIRD_NEIBOUR ] += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
} \
} \
} \
}
/***************************************************************/
#define BINARY_TREE_SEARCH_LEFT( POSITION, SHIFT ) \
{ \
if( ( distance > ( ( ( position[ POSITION ] - c[ POSITION ] ) * \
( position[ POSITION ] - c[ POSITION ] ) ) >> SHIFT ) ) && \
position[ POSITION ] ) \
continue_up = 1; \
}
/***************************************************************/
#define BINARY_TREE_EXPLORE_LEFT_3( POSITION, IMAGE_TYPE, \
FIRST_NEIBOUR, SECOND_NEIBOUR, SUBSTRACTION, SHIFT ) \
{ \
if( distance > \
( ( ( c[ POSITION ] - position[ POSITION ] ) * \
( c[ POSITION ] - position[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance <= ( ( c[ POSITION ] * c[ POSITION ] ) >> SHIFT ) ) \
{ \
if( distance <= ( ( ( c[ POSITION ] + current_size - \
position[ POSITION ] ) * \
( c[ POSITION ] + current_size - \
position[ POSITION ] ) ) >> SHIFT ) ) \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_corner += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_right_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] - current_size, pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_corner += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], p ); \
} \
} \
else \
{ \
if( !( position[ POSITION ] - current_size ) ) \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_corner += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_right_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] - current_size, pass - 1, POSITION ); \
} \
else \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_corner += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_3( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], p ); \
} \
} \
} \
}
/***************************************************************/
#define BINARY_TREE_EXPLORE_LEFT_4( POSITION, IMAGE_TYPE, \
FIRST_NEIBOUR, SECOND_NEIBOUR, THIRD_NEIBOUR, SUBSTRACTION, SHIFT ) \
{ \
if( distance > \
( ( ( c[ POSITION ] - position[ POSITION ] ) * \
( c[ POSITION ] - position[ POSITION ] ) ) >> SHIFT ) ) \
{ \
if( distance <= ( ( c[ POSITION ] * c[ POSITION ] ) >> SHIFT ) ) \
{ \
if( distance <= ( ( ( c[ POSITION ] + current_size - \
position[ POSITION ] ) * \
( c[ POSITION ] + current_size - \
position[ POSITION ] ) ) >> SHIFT ) ) \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_neibours[ THIRD_NEIBOUR ] += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_right_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] - current_size, pass - 1, POSITION ); \
} \
else /* Check whole quadrant */ \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_neibours[ THIRD_NEIBOUR ] += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
} \
} \
else \
{ \
if( !( position[ POSITION ] - current_size ) ) \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 1; \
check_neibours[ SECOND_NEIBOUR ] += 1; \
check_neibours[ THIRD_NEIBOUR ] += 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Only a part of quadrant needs checking */ \
distance = \
mlib_search_quadrant_part_to_right_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c, p, \
position[ POSITION ] - current_size, pass - 1, POSITION ); \
} \
else \
{ \
mlib_s32 qq = q ^ ( 1 << POSITION ); \
\
check_neibours[ FIRST_NEIBOUR ] += 2; \
check_neibours[ SECOND_NEIBOUR ] += 2; \
check_neibours[ THIRD_NEIBOUR ] += 2; \
continue_up = 1; \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. \
Check the distance */ \
mlib_s32 new_found_color = \
node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ] - SUBSTRACTION, c[ 1 ], \
p[ 1 ][ new_found_color ] - SUBSTRACTION, c[ 2 ], \
p[ 2 ][ new_found_color ] - SUBSTRACTION, c[ 3 ], \
p[ 3 ][ new_found_color ] - SUBSTRACTION, SHIFT ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it */ \
distance = mlib_search_quadrant_##IMAGE_TYPE##_4( \
node->contents.quadrants[ qq ], \
distance, &found_color, c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
} \
} \
} \
}
/***************************************************************/
#define CHECK_QUADRANT_U8_3( qq ) \
{ \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. Check the distance */ \
mlib_s32 new_found_color = node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_3( c[ 0 ], \
p[ 0 ][ new_found_color ], c[ 1 ], \
p[ 1 ][ new_found_color ], c[ 2 ], \
p[ 2 ][ new_found_color ], 0 ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it all */ \
distance = mlib_search_quadrant_U8_3( \
node->contents.quadrants[ qq ], distance, &found_color, \
c[ 0 ], c[ 1 ], c[ 2 ], p ); \
/* Else there is just an empty cell */ \
}
/***************************************************************/
#define CHECK_QUADRANT_S16_3( qq ) \
{ \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. Check the distance */ \
mlib_s32 new_found_color = node->contents.index[ qq ]; \
mlib_u32 palc0, palc1, palc2, newdistance; \
\
palc0 = p[ 0 ][ new_found_color ] - MLIB_S16_MIN; \
palc1 = p[ 1 ][ new_found_color ] - MLIB_S16_MIN; \
palc2 = p[ 2 ][ new_found_color ] - MLIB_S16_MIN; \
\
newdistance = FIND_DISTANCE_3( c[ 0 ], palc0, \
c[ 1 ], palc1, \
c[ 2 ], palc2, 2 ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it all */ \
distance = mlib_search_quadrant_S16_3( \
node->contents.quadrants[ qq ], distance, &found_color, \
c[ 0 ], c[ 1 ], c[ 2 ], p ); \
/* Else there is just an empty cell */ \
}
/***************************************************************/
#define BINARY_TREE_SEARCH_3( SOURCE_IMAGE, POINTER_TYPE, BITS, \
COLOR_MAX, SUBTRACTION, POINTER_SHIFT, STEP, SHIFT ) \
{ \
const POINTER_TYPE *channels[ 3 ], *p[ 3 ]; \
mlib_u32 c[ 3 ]; \
mlib_s32 j; \
\
p[ 0 ] = s->lut[ 0 ]; \
p[ 1 ] = s->lut[ 1 ]; \
p[ 2 ] = s->lut[ 2 ]; \
channels[ 0 ] = src + POINTER_SHIFT; \
channels[ 1 ] = src + 1 + POINTER_SHIFT; \
channels[ 2 ] = src + 2 + POINTER_SHIFT; \
\
for( j = 0; j < length; j++ ) \
{ \
mlib_s32 pass = BITS - 1; \
mlib_u32 position[ 3 ] = { 0, 0, 0 }; \
mlib_s32 we_found_it = 0; \
struct lut_node_3 *node = s->table; \
/* Stack pointer pointers to the first free element of stack. */ \
/* The node we are in is in the `node' */ \
struct \
{ \
struct lut_node_3 *node; \
mlib_s32 q; \
} stack[ BITS ]; \
mlib_s32 stack_pointer = 0; \
\
c[ 0 ] = *channels[ 0 ] - SUBTRACTION; \
c[ 1 ] = *channels[ 1 ] - SUBTRACTION; \
c[ 2 ] = *channels[ 2 ] - SUBTRACTION; \
\
do \
{ \
mlib_s32 q; \
mlib_u32 current_size = 1 << pass; \
\
q = ( ( c[ 0 ] >> pass ) & 1 ) | \
( ( ( c[ 1 ] << 1 ) >> pass ) & 2 ) | \
( ( ( c[ 2 ] << 2 ) >> pass ) & 4 ); \
\
position[ 0 ] |= c[ 0 ] & current_size; \
position[ 1 ] |= c[ 1 ] & current_size; \
position[ 2 ] |= c[ 2 ] & current_size; \
\
if( node->tag & ( 1 << q ) ) \
{ \
/* \
Here is a cell with one color. We need to be sure it's \
the one that is the closest to our color \
*/ \
mlib_s32 palindex = node->contents.index[ q ]; \
mlib_u32 palc[ 3 ]; \
mlib_s32 identical; \
\
palc[ 0 ] = p[ 0 ][ palindex ] - SUBTRACTION; \
palc[ 1 ] = p[ 1 ][ palindex ] - SUBTRACTION; \
palc[ 2 ] = p[ 2 ][ palindex ] - SUBTRACTION; \
\
identical = ( palc[ 0 ] - c[ 0 ] ) | ( palc[ 1 ] - c[ 1 ] ) | \
( palc[ 2 ] - c[ 2 ] ); \
\
if( !identical || BITS - pass == bits ) \
{ \
/* Oh, here it is :) */ \
dst[ j ] = palindex + s->offset; \
we_found_it = 1; \
} \
else \
{ \
mlib_u32 distance; \
/* First index is the channel, second is the number of the \
side */ \
mlib_s32 found_color; \
mlib_s32 continue_up; \
\
distance = FIND_DISTANCE_3( c[ 0 ], palc[ 0 ], \
c[ 1 ], palc[ 1 ], c[ 2 ], palc[ 2 ], SHIFT ); \
found_color = palindex; \
\
do \
{ \
mlib_s32 check_corner; \
\
/* \
Neibours are enumerated in a cicle: \
0 - between quadrants 0 and 1, \
1 - between quadrants 1 and 2 and \
2 - between quadrants 2 and 0 \
*/ \
mlib_s32 check_neibours[ 3 ]; \
\
/* \
Others are three two neibour quadrants \
\
Side number is [ <number of the coordinate >][ <the bit \
in the quadrant number of the corner, corresponding to \
this coordinate> ], e.g. 2 is 0..010b, so the sides it has \
near are: \
[ 0 (coordinate number) ][ 0 (bit 0 in the number) ] \
[ 1 (coordinate number) ][ 1 (bit 1 in the number) ] \
\
Now we can look in the three nearest quadrants. Do \
we really need it ? Check it. \
*/ \
\
check_corner = check_neibours[ 0 ] = check_neibours[ 1 ] = \
check_neibours[ 2 ] = 0; \
continue_up = 0; \
\
if( q & 1 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 0, SOURCE_IMAGE, 2, 0, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 0, COLOR_MAX, SOURCE_IMAGE, 2, 0, \
SUBTRACTION, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 1, SOURCE_IMAGE, 0, 1, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 1, COLOR_MAX, SOURCE_IMAGE, 0, 1, \
SUBTRACTION, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 2, SOURCE_IMAGE, 1, 2, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 2, COLOR_MAX, SOURCE_IMAGE, 1, 2, \
SUBTRACTION, SHIFT ); \
} \
\
if( check_neibours[ 0 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 3; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_neibours[ 1 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 6; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_neibours[ 2 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 5; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_corner >= 3 ) \
{ \
mlib_s32 qq = q ^ 7; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( q & 1 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 0, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 0, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 1, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 1, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 2, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 2, SHIFT ); \
} \
\
position[ 0 ] &= ~( c[ 0 ] & current_size ); \
position[ 1 ] &= ~( c[ 1 ] & current_size ); \
position[ 2 ] &= ~( c[ 2 ] & current_size ); \
\
current_size <<= 1; \
\
pass++; \
\
stack_pointer--; \
q = stack[ stack_pointer ].q; \
node = stack[ stack_pointer ].node; \
} while( continue_up ); \
\
dst[ j ] = found_color + s->offset; \
\
we_found_it = 1; \
} \
} \
else if( node->contents.quadrants[ q ] ) \
{ \
/* Descend one level */ \
stack[ stack_pointer ].node = node; \
stack[ stack_pointer++ ].q = q; \
node = node->contents.quadrants[ q ]; \
} \
else \
{ \
/* Found the empty quadrant. Look around */ \
mlib_u32 distance = MLIB_U32_MAX; \
mlib_s32 found_color; \
mlib_s32 continue_up; \
\
/* \
As we had come to this level, it is warranted that there \
are other points on this level near the empty quadrant \
*/ \
do \
{ \
mlib_s32 check_corner; \
mlib_s32 check_neibours[ 3 ]; \
\
check_corner = check_neibours[ 0 ] = check_neibours[ 1 ] = \
check_neibours[ 2 ] = 0; \
continue_up = 0; \
\
if( q & 1 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 0, SOURCE_IMAGE, 2, 0, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 0, COLOR_MAX, SOURCE_IMAGE, 2, 0, \
SUBTRACTION, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 1, SOURCE_IMAGE, 0, 1, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 1, COLOR_MAX, SOURCE_IMAGE, 0, 1, \
SUBTRACTION, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_3( 2, SOURCE_IMAGE, 1, 2, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_3( 2, COLOR_MAX, SOURCE_IMAGE, 1, 2, \
SUBTRACTION, SHIFT ); \
} \
\
if( check_neibours[ 0 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 3; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_neibours[ 1 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 6; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_neibours[ 2 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 5; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( check_corner >= 3 ) \
{ \
mlib_s32 qq = q ^ 7; \
CHECK_QUADRANT_##SOURCE_IMAGE##_3( qq ); \
} \
\
if( q & 1 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 0, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 0, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 1, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 1, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 2, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 2, SHIFT ); \
} \
\
position[ 0 ] &= ~( c[ 0 ] & current_size ); \
position[ 1 ] &= ~( c[ 1 ] & current_size ); \
position[ 2 ] &= ~( c[ 2 ] & current_size ); \
\
current_size <<= 1; \
\
pass++; \
\
stack_pointer--; \
q = stack[ stack_pointer ].q; \
node = stack[ stack_pointer ].node; \
} while( continue_up ); \
\
dst[ j ] = found_color + s->offset; \
we_found_it = 1; \
} \
\
pass--; \
\
} while( !we_found_it ); \
\
channels[ 0 ] += STEP; \
channels[ 1 ] += STEP; \
channels[ 2 ] += STEP; \
} \
}
/***************************************************************/
#define CHECK_QUADRANT_U8_4( qq ) \
{ \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. Check the distance */ \
mlib_s32 new_found_color = node->contents.index[ qq ]; \
mlib_u32 newdistance = FIND_DISTANCE_4( c[ 0 ], \
p[ 0 ][ new_found_color ], c[ 1 ], \
p[ 1 ][ new_found_color ], c[ 2 ], \
p[ 2 ][ new_found_color ], c[ 3 ], \
p[ 3 ][ new_found_color ], 0 ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it all */ \
distance = mlib_search_quadrant_U8_4( \
node->contents.quadrants[ qq ], distance, &found_color, \
c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
/* Else there is just an empty cell */ \
}
/***************************************************************/
#define CHECK_QUADRANT_S16_4( qq ) \
{ \
if( node->tag & ( 1 << qq ) ) \
{ \
/* Here is another color cell. Check the distance */ \
mlib_s32 new_found_color = node->contents.index[ qq ]; \
mlib_u32 palc0, palc1, palc2, palc3, newdistance; \
\
palc0 = p[ 0 ][ new_found_color ] - MLIB_S16_MIN; \
palc1 = p[ 1 ][ new_found_color ] - MLIB_S16_MIN; \
palc2 = p[ 2 ][ new_found_color ] - MLIB_S16_MIN; \
palc3 = p[ 3 ][ new_found_color ] - MLIB_S16_MIN; \
\
newdistance = FIND_DISTANCE_4( c[ 0 ], palc0, \
c[ 1 ], palc1, \
c[ 2 ], palc2, \
c[ 3 ], palc3, 2 ); \
\
if( newdistance < distance ) \
{ \
found_color = new_found_color; \
distance = newdistance; \
} \
} \
else if( node->contents.quadrants[ qq ] ) \
/* Here is a full node. Just explore it all */ \
distance = mlib_search_quadrant_S16_4( \
node->contents.quadrants[ qq ], distance, &found_color, \
c[ 0 ], c[ 1 ], c[ 2 ], c[ 3 ], p ); \
/* Else there is just an empty cell */ \
}
/***************************************************************/
#define BINARY_TREE_SEARCH_4( SOURCE_IMAGE, POINTER_TYPE, BITS, \
COLOR_MAX, SUBTRACTION, SHIFT ) \
{ \
const POINTER_TYPE *channels[ 4 ], *p[ 4 ]; \
mlib_u32 c[ 4 ]; \
mlib_s32 j; \
\
p[ 0 ] = s->lut[ 0 ]; \
p[ 1 ] = s->lut[ 1 ]; \
p[ 2 ] = s->lut[ 2 ]; \
p[ 3 ] = s->lut[ 3 ]; \
channels[ 0 ] = src; \
channels[ 1 ] = src + 1; \
channels[ 2 ] = src + 2; \
channels[ 3 ] = src + 3; \
\
for( j = 0; j < length; j++ ) \
{ \
mlib_s32 pass = BITS - 1; \
mlib_u32 position[ 4 ] = { 0, 0, 0, 0 }; \
mlib_s32 we_found_it = 0; \
struct lut_node_4 *node = s->table; \
/* Stack pointer pointers to the first free element of stack. */ \
/* The node we are in is in the `node' */ \
struct \
{ \
struct lut_node_4 *node; \
mlib_s32 q; \
} stack[ BITS ]; \
mlib_s32 stack_pointer = 0; \
\
c[ 0 ] = *channels[ 0 ] - SUBTRACTION; \
c[ 1 ] = *channels[ 1 ] - SUBTRACTION; \
c[ 2 ] = *channels[ 2 ] - SUBTRACTION; \
c[ 3 ] = *channels[ 3 ] - SUBTRACTION; \
\
do \
{ \
mlib_s32 q; \
mlib_u32 current_size = 1 << pass; \
\
q = ( ( c[ 0 ] >> pass ) & 1 ) | \
( ( ( c[ 1 ] << 1 ) >> pass ) & 2 ) | \
( ( ( c[ 2 ] << 2 ) >> pass ) & 4 ) | \
( ( ( c[ 3 ] << 3 ) >> pass ) & 8 ); \
\
position[ 0 ] |= c[ 0 ] & current_size; \
position[ 1 ] |= c[ 1 ] & current_size; \
position[ 2 ] |= c[ 2 ] & current_size; \
position[ 3 ] |= c[ 3 ] & current_size; \
\
if( node->tag & ( 1 << q ) ) \
{ \
/* \
Here is a cell with one color. We need to be sure it's \
the one that is the closest to our color \
*/ \
mlib_s32 palindex = node->contents.index[ q ]; \
mlib_u32 palc[ 4 ]; \
mlib_s32 identical; \
\
palc[ 0 ] = p[ 0 ][ palindex ] - SUBTRACTION; \
palc[ 1 ] = p[ 1 ][ palindex ] - SUBTRACTION; \
palc[ 2 ] = p[ 2 ][ palindex ] - SUBTRACTION; \
palc[ 3 ] = p[ 3 ][ palindex ] - SUBTRACTION; \
\
identical = ( palc[ 0 ] - c[ 0 ] ) | ( palc[ 1 ] - c[ 1 ] ) | \
( palc[ 2 ] - c[ 2 ] ) | ( palc[ 3 ] - c[ 3 ] ); \
\
if( !identical || BITS - pass == bits ) \
{ \
/* Oh, here it is :) */ \
dst[ j ] = palindex + s->offset; \
we_found_it = 1; \
} \
else \
{ \
mlib_u32 distance; \
/* First index is the channel, second is the number of the \
side */ \
mlib_s32 found_color; \
mlib_s32 continue_up; \
\
distance = FIND_DISTANCE_4( c[ 0 ], palc[ 0 ], \
c[ 1 ], palc[ 1 ], c[ 2 ], palc[ 2 ], c[ 3 ], palc[ 3 ], SHIFT ); \
found_color = palindex; \
\
do \
{ \
mlib_s32 check_corner; \
mlib_s32 check_neibours[ 6 ]; \
mlib_s32 check_far_neibours[ 4 ]; \
\
/* \
Check neibours: quadrants that are different by 2 bits \
from the quadrant, that we are in: \
3 - 0 \
5 - 1 \
6 - 2 \
9 - 3 \
10 - 4 \
12 - 5 \
Far quadrants: different by 3 bits: \
7 - 0 \
11 - 1 \
13 - 2 \
14 - 3 \
*/ \
\
check_neibours[ 0 ] = check_neibours[ 1 ] = \
check_neibours[ 2 ] = check_neibours[ 3 ] = \
check_neibours[ 4 ] = check_neibours[ 5 ] = 0; \
continue_up = 0; \
\
if( q & 1 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 0, SOURCE_IMAGE, 0, 1, 3, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 0, COLOR_MAX, SOURCE_IMAGE, \
0, 1, 3, SUBTRACTION, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 1, SOURCE_IMAGE, 0, 2, 4, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 1, COLOR_MAX, SOURCE_IMAGE, \
0, 2, 4, SUBTRACTION, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 2, SOURCE_IMAGE, 1, 2, 5, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 2, COLOR_MAX, SOURCE_IMAGE, \
1, 2, 5, SUBTRACTION, SHIFT ); \
} \
\
if( q & 8 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 3, SOURCE_IMAGE, 3, 4, 5, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 3, COLOR_MAX, SOURCE_IMAGE, \
3, 4, 5, SUBTRACTION, SHIFT ); \
} \
\
check_far_neibours[ 0 ] = check_neibours[ 0 ] + \
check_neibours[ 1 ] + check_neibours[ 2 ]; \
check_far_neibours[ 1 ] = check_neibours[ 0 ] + \
check_neibours[ 3 ] + check_neibours[ 4 ]; \
check_far_neibours[ 2 ] = check_neibours[ 1 ] + \
check_neibours[ 3 ] + check_neibours[ 5 ]; \
check_far_neibours[ 3 ] = check_neibours[ 2 ] + \
check_neibours[ 4 ] + check_neibours[ 5 ]; \
\
check_corner = check_far_neibours[ 0 ] + \
check_far_neibours[ 1 ] + \
check_far_neibours[ 2 ] + \
check_far_neibours[ 3 ]; \
\
if( check_neibours[ 0 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 3; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 1 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 5; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 2 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 6; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 3 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 9; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 4 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 10; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 5 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 12; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 0 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 7; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 1 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 11; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 2 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 13; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 3 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 14; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_corner >= 4 ) \
{ \
mlib_s32 qq = q ^ 15; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( q & 1 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 0, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 0, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 1, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 1, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 2, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 2, SHIFT ); \
} \
\
if( q & 8 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 3, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 3, SHIFT ); \
} \
\
position[ 0 ] &= ~( c[ 0 ] & current_size ); \
position[ 1 ] &= ~( c[ 1 ] & current_size ); \
position[ 2 ] &= ~( c[ 2 ] & current_size ); \
position[ 3 ] &= ~( c[ 3 ] & current_size ); \
\
current_size <<= 1; \
\
pass++; \
\
stack_pointer--; \
q = stack[ stack_pointer ].q; \
node = stack[ stack_pointer ].node; \
} while( continue_up ); \
\
dst[ j ] = found_color + s->offset; \
we_found_it = 1; \
} \
} \
else if( node->contents.quadrants[ q ] ) \
{ \
/* Descend one level */ \
stack[ stack_pointer ].node = node; \
stack[ stack_pointer++ ].q = q; \
node = node->contents.quadrants[ q ]; \
} \
else \
{ \
/* Found the empty quadrant. Look around */ \
mlib_u32 distance = MLIB_U32_MAX; \
mlib_s32 found_color; \
mlib_s32 continue_up; \
\
/* \
As we had come to this level, it is warranted that there \
are other points on this level near the empty quadrant \
*/ \
do \
{ \
mlib_s32 check_corner; \
mlib_s32 check_neibours[ 6 ]; \
mlib_s32 check_far_neibours[ 4 ]; \
\
/* \
Check neibours: quadrants that are different by 2 bits \
from the quadrant, that we are in: \
3 - 0 \
5 - 1 \
6 - 2 \
9 - 3 \
10 - 4 \
12 - 5 \
Far quadrants: different by 3 bits: \
7 - 0 \
11 - 1 \
13 - 2 \
14 - 3 \
*/ \
\
check_neibours[ 0 ] = check_neibours[ 1 ] = \
check_neibours[ 2 ] = check_neibours[ 3 ] = \
check_neibours[ 4 ] = check_neibours[ 5 ] = 0; \
continue_up = 0; \
\
if( q & 1 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 0, SOURCE_IMAGE, 0, 1, 3, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 0, COLOR_MAX, SOURCE_IMAGE, \
0, 1, 3, SUBTRACTION, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 1, SOURCE_IMAGE, 0, 2, 4, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 1, COLOR_MAX, SOURCE_IMAGE, \
0, 2, 4, SUBTRACTION, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 2, SOURCE_IMAGE, 1, 2, 5, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 2, COLOR_MAX, SOURCE_IMAGE, \
1, 2, 5, SUBTRACTION, SHIFT ); \
} \
\
if( q & 8 ) \
{ \
BINARY_TREE_EXPLORE_LEFT_4( 3, SOURCE_IMAGE, 3, 4, 5, \
SUBTRACTION, SHIFT ); \
} \
else \
{ \
BINARY_TREE_EXPLORE_RIGHT_4( 3, COLOR_MAX, SOURCE_IMAGE, \
3, 4, 5, SUBTRACTION, SHIFT ); \
} \
\
check_far_neibours[ 0 ] = check_neibours[ 0 ] + \
check_neibours[ 1 ] + check_neibours[ 2 ]; \
check_far_neibours[ 1 ] = check_neibours[ 0 ] + \
check_neibours[ 3 ] + check_neibours[ 4 ]; \
check_far_neibours[ 2 ] = check_neibours[ 1 ] + \
check_neibours[ 3 ] + check_neibours[ 5 ]; \
check_far_neibours[ 3 ] = check_neibours[ 2 ] + \
check_neibours[ 4 ] + check_neibours[ 5 ]; \
\
check_corner = check_far_neibours[ 0 ] + \
check_far_neibours[ 1 ] + \
check_far_neibours[ 2 ] + \
check_far_neibours[ 3 ]; \
\
if( check_neibours[ 0 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 3; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 1 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 5; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 2 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 6; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 3 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 9; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 4 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 10; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_neibours[ 5 ] >= 2 ) \
{ \
mlib_s32 qq = q ^ 12; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 0 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 7; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 1 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 11; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 2 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 13; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_far_neibours[ 3 ] >= 3 ) \
{ \
mlib_s32 qq = q ^ 14; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( check_corner >= 4 ) \
{ \
mlib_s32 qq = q ^ 15; \
CHECK_QUADRANT_##SOURCE_IMAGE##_4( qq ); \
} \
\
if( q & 1 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 0, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 0, SHIFT ); \
} \
\
if( q & 2 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 1, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 1, SHIFT ); \
} \
\
if( q & 4 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 2, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 2, SHIFT ); \
} \
\
if( q & 8 ) \
{ \
BINARY_TREE_SEARCH_RIGHT( 3, COLOR_MAX, SHIFT ); \
} \
else \
{ \
BINARY_TREE_SEARCH_LEFT( 3, SHIFT ); \
} \
\
position[ 0 ] &= ~( c[ 0 ] & current_size ); \
position[ 1 ] &= ~( c[ 1 ] & current_size ); \
position[ 2 ] &= ~( c[ 2 ] & current_size ); \
position[ 3 ] &= ~( c[ 3 ] & current_size ); \
\
current_size <<= 1; \
\
pass++; \
\
stack_pointer--; \
q = stack[ stack_pointer ].q; \
node = stack[ stack_pointer ].node; \
} while( continue_up ); \
\
dst[ j ] = found_color + s->offset; \
we_found_it = 1; \
} \
\
pass--; \
\
} while( !we_found_it ); \
\
channels[ 0 ] += 4; \
channels[ 1 ] += 4; \
channels[ 2 ] += 4; \
channels[ 3 ] += 4; \
} \
}
/***************************************************************/
#define FIND_NEAREST_U8_3_C( SHIFT, STEP ) \
mlib_s32 i, k, k_min, min_dist, diff, mask; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s -> lutlength; \
mlib_d64 *double_lut = mlib_ImageGetLutDoubleData( s ); \
mlib_d64 col0, col1, col2; \
mlib_d64 dist, len0, len1, len2; \
\
for ( i = 0; i < length; i++ ) { \
col0 = src[ STEP * i + SHIFT ]; \
col1 = src[ STEP * i + 1 + SHIFT ]; \
col2 = src[ STEP * i + 2 + SHIFT ]; \
min_dist = MLIB_S32_MAX; \
k_min = 1; \
len0 = double_lut[ 0 ] - col0; \
len1 = double_lut[ 1 ] - col1; \
len2 = double_lut[ 2 ] - col2; \
\
for ( k = 1; k <= entries; k++ ) { \
dist = len0 * len0; \
len0 = double_lut[ 3 * k ] - col0; \
dist += len1 * len1; \
len1 = double_lut[ 3 * k + 1 ] - col1; \
dist += len2 * len2; \
len2 = double_lut[ 3 * k + 2 ] - col2; \
diff = ( mlib_s32 )dist - min_dist; \
mask = diff >> 31; \
min_dist += diff & mask; \
k_min += ( k - k_min ) & mask; \
} \
\
dst[ i ] = k_min + offset; \
}
/***************************************************************/
#define FIND_NEAREST_U8_4_C \
mlib_s32 i, k, k_min, min_dist, diff, mask; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s -> lutlength; \
mlib_d64 *double_lut = mlib_ImageGetLutDoubleData( s ); \
mlib_d64 col0, col1, col2, col3; \
mlib_d64 dist, len0, len1, len2, len3; \
\
for ( i = 0; i < length; i++ ) { \
col0 = src[ 4 * i ]; \
col1 = src[ 4 * i + 1 ]; \
col2 = src[ 4 * i + 2 ]; \
col3 = src[ 4 * i + 3 ]; \
min_dist = MLIB_S32_MAX; \
k_min = 1; \
len0 = double_lut[ 0 ] - col0; \
len1 = double_lut[ 1 ] - col1; \
len2 = double_lut[ 2 ] - col2; \
len3 = double_lut[ 3 ] - col3; \
\
for ( k = 1; k <= entries; k++ ) { \
dist = len0 * len0; \
len0 = double_lut[ 4 * k ] - col0; \
dist += len1 * len1; \
len1 = double_lut[ 4 * k + 1 ] - col1; \
dist += len2 * len2; \
len2 = double_lut[ 4 * k + 2 ] - col2; \
dist += len3 * len3; \
len3 = double_lut[ 4 * k + 3 ] - col3; \
diff = ( mlib_s32 )dist - min_dist; \
mask = diff >> 31; \
min_dist += diff & mask; \
k_min += ( k - k_min ) & mask; \
} \
\
dst[ i ] = k_min + offset; \
}
/***************************************************************/
#define FSQR_S16_HI(dsrc) \
vis_fpadd32( vis_fmuld8ulx16( vis_read_hi( dsrc ), vis_read_hi( dsrc ) ), \
vis_fmuld8sux16( vis_read_hi( dsrc ), vis_read_hi( dsrc ) ) )
/***************************************************************/
#define FSQR_S16_LO(dsrc) \
vis_fpadd32( vis_fmuld8ulx16( vis_read_lo( dsrc ), vis_read_lo( dsrc) ), \
vis_fmuld8sux16( vis_read_lo( dsrc ), vis_read_lo( dsrc ) ) )
/***************************************************************/
#define FIND_NEAREST_U8_3 \
{ \
mlib_d64 *dpsrc, dsrc, dsrc1, ddist, ddist1, ddist2, ddist3; \
mlib_d64 dcolor, dind, dres, dres1, dpind[1], dpmin[1]; \
mlib_d64 done = vis_to_double_dup( 1 ), \
dmax = vis_to_double_dup( MLIB_S32_MAX ); \
mlib_f32 *lut = ( mlib_f32 * )mlib_ImageGetLutNormalTable( s ); \
mlib_f32 fone = vis_to_float( 0x100 ); \
mlib_s32 i, k, mask; \
mlib_s32 gsr[1]; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s->lutlength; \
\
gsr[0] = vis_read_gsr(); \
for( i = 0; i <= ( length-2 ); i += 2 ) \
{ \
dpsrc = VIS_ALIGNADDR( src, -1 ); \
src += 6; \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
VIS_ALIGNADDR( dpsrc, 3 ); \
dsrc1 = vis_faligndata( dsrc1, dsrc1 ); \
dsrc1 = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
dcolor = vis_fmul8x16al( lut[ 0 ], fone ); \
for( k = 1; k <= entries; k++ ) \
{ \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
ddist3 = vis_fpsub16( dcolor, dsrc1 ); \
ddist2 = FSQR_S16_HI( ddist3 ); \
ddist3 = FSQR_S16_LO( ddist3 ); \
dres1 = vis_fpadd32( ddist2, ddist3 ); \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
dres = vis_freg_pair( \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ), \
vis_fpadd32s( vis_read_hi( dres1 ), vis_read_lo( dres1 ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind )[ 0 ] + offset; \
dst[ i + 1 ] = ( ( mlib_s32 * )dpind)[ 1 ] + offset; \
} \
if( i < length ) \
{ \
dpsrc = VIS_ALIGNADDR( src, -1 ); \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
for( k = 0; k < entries; k++ ) \
{ \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
dres = vis_write_lo( dres, \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind)[ 1 ] + offset; \
} \
vis_write_gsr(gsr[0]); \
}
/***************************************************************/
#define FIND_NEAREST_U8_3_IN4 \
{ \
mlib_d64 *dpsrc, dsrc, dsrc1, ddist, ddist1, ddist2, ddist3; \
mlib_d64 dcolor, dind, dres, dres1, dpind[1], dpmin[1]; \
mlib_d64 done = vis_to_double_dup( 1 ), \
dmax = vis_to_double_dup( MLIB_S32_MAX ); \
mlib_f32 *lut = ( mlib_f32 * )mlib_ImageGetLutNormalTable( s ); \
mlib_f32 fone = vis_to_float( 0x100 ); \
mlib_s32 i, k, mask, gsr[1]; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s->lutlength; \
\
gsr[0] = vis_read_gsr(); \
dpsrc = VIS_ALIGNADDR( src, 0 ); \
for( i = 0; i <= ( length-2 ); i += 2 ) \
{ \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dpsrc++; \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dsrc1 = vis_fmul8x16al( vis_read_lo( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
dcolor = vis_fmul8x16al( lut[ 0 ], fone ); \
for( k = 1; k <= entries; k++ ) \
{ \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
ddist3 = vis_fpsub16( dcolor, dsrc1 ); \
ddist2 = FSQR_S16_HI( ddist3 ); \
ddist3 = FSQR_S16_LO( ddist3 ); \
dres1 = vis_fpadd32( ddist2, ddist3 ); \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
dres = vis_freg_pair( \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ), \
vis_fpadd32s( vis_read_hi( dres1 ), vis_read_lo( dres1 ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind )[ 0 ] + offset; \
dst[ i + 1 ] = ( ( mlib_s32 * )dpind)[ 1 ] + offset; \
} \
if( i < length ) \
{ \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
for( k = 0; k < entries; k++ ) \
{ \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
dres = vis_write_lo( dres, \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind)[ 1 ] + offset; \
} \
vis_write_gsr(gsr[0]); \
}
/***************************************************************/
#define FIND_NEAREST_U8_4 \
{ \
mlib_d64 *dpsrc, dsrc, dsrc1, ddist, ddist1, ddist2, ddist3; \
mlib_d64 dcolor, dind, dres, dres1, dpind[ 1 ], dpmin[ 1 ]; \
mlib_d64 done = vis_to_double_dup( 1 ), \
dmax = vis_to_double_dup( MLIB_S32_MAX ); \
mlib_f32 *lut = ( mlib_f32 * )mlib_ImageGetLutNormalTable( s ); \
mlib_f32 fone = vis_to_float( 0x100 ); \
mlib_s32 i, k, mask, gsr[1]; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s->lutlength; \
\
gsr[0] = vis_read_gsr(); \
dpsrc = VIS_ALIGNADDR( src, 0 ); \
for( i = 0; i <= ( length-2 ); i += 2 ) \
{ \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dpsrc++; \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dsrc1 = vis_fmul8x16al( vis_read_lo( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
dcolor = vis_fmul8x16al(lut[0], fone); \
for( k = 1; k <= entries; k++ ) \
{ \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
ddist3 = vis_fpsub16( dcolor, dsrc1 ); \
ddist2 = FSQR_S16_HI( ddist3 ); \
ddist3 = FSQR_S16_LO( ddist3 ); \
dres1 = vis_fpadd32( ddist2, ddist3 ); \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
dres = vis_freg_pair( \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ), \
vis_fpadd32s( vis_read_hi( dres1 ), vis_read_lo( dres1 ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind )[ 0 ] + offset; \
dst[ i + 1 ] = ( ( mlib_s32 * )dpind )[ 1 ] + offset; \
} \
if( i < length ) \
{ \
dsrc = dpsrc[ 0 ]; \
dsrc1 = dpsrc[ 1 ]; \
dsrc1 = vis_faligndata( dsrc, dsrc1 ); \
dsrc = vis_fmul8x16al( vis_read_hi( dsrc1 ), fone ); \
dpind[ 0 ] = dind = done; \
dpmin[ 0 ] = dmax; \
for( k = 0; k < entries; k++ ) \
{ \
dcolor = vis_fmul8x16al( lut[ k ], fone ); \
ddist1 = vis_fpsub16( dcolor, dsrc ); \
ddist = FSQR_S16_HI( ddist1 ); \
ddist1 = FSQR_S16_LO( ddist1 ); \
dres = vis_fpadd32( ddist, ddist1 ); \
dres = vis_write_lo( dres, \
vis_fpadd32s( vis_read_hi( dres ), vis_read_lo( dres ) ) ); \
mask = vis_fcmplt32( dres, dpmin[ 0 ] ); \
vis_pst_32( dind, ( void * )dpind, mask ); \
dind = vis_fpadd32( dind, done ); \
vis_pst_32( dres, ( void * )dpmin, mask ); \
} \
dst[ i ] = ( ( mlib_s32 * )dpind )[ 1 ] + offset; \
} \
vis_write_gsr(gsr[0]); \
}
/***************************************************************/
#define FIND_NEAREST_S16_3( SHIFT, STEP ) \
mlib_s32 i, k, k_min, min_dist, diff, mask; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s->lutlength; \
mlib_d64 *double_lut = mlib_ImageGetLutDoubleData( s ); \
mlib_d64 col0, col1, col2; \
mlib_d64 dist, len0, len1, len2; \
\
for( i = 0; i < length; i++ ) \
{ \
col0 = src[ STEP * i + SHIFT ]; \
col1 = src[ STEP * i + 1 + SHIFT ]; \
col2 = src[ STEP * i + 2 + SHIFT ]; \
min_dist = MLIB_S32_MAX; \
k_min = 1; \
len0 = double_lut[ 0 ] - col0; \
len1 = double_lut[ 1 ] - col1; \
len2 = double_lut[ 2 ] - col2; \
for( k = 1; k <= entries; k++ ) \
{ \
dist = len0 * len0; \
len0 = double_lut[ 3 * k ] - col0; \
dist += len1 * len1; \
len1 = double_lut[ 3 * k + 1 ] - col1; \
dist += len2 * len2; \
len2 = double_lut[ 3 * k + 2 ] - col2; \
diff = ( mlib_s32 )( dist * 0.125 ) - min_dist; \
mask = diff >> 31; \
min_dist += diff & mask; \
k_min += ( k - k_min ) & mask; \
} \
dst[ i ] = k_min + offset; \
}
/***************************************************************/
#define FIND_NEAREST_S16_4 \
mlib_s32 i, k, k_min, min_dist, diff, mask; \
mlib_s32 offset = mlib_ImageGetLutOffset( s ) - 1; \
mlib_s32 entries = s->lutlength; \
mlib_d64 *double_lut = mlib_ImageGetLutDoubleData( s ); \
mlib_d64 col0, col1, col2, col3; \
mlib_d64 dist, len0, len1, len2, len3; \
\
for( i = 0; i < length; i++ ) \
{ \
col0 = src[ 4 * i ]; \
col1 = src[ 4 * i + 1 ]; \
col2 = src[ 4 * i + 2 ]; \
col3 = src[ 4 * i + 3 ]; \
min_dist = MLIB_S32_MAX; \
k_min = 1; \
len0 = double_lut[ 0 ] - col0; \
len1 = double_lut[ 1 ] - col1; \
len2 = double_lut[ 2 ] - col2; \
len3 = double_lut[ 3 ] - col3; \
for( k = 1; k <= entries; k++ ) \
{ \
dist = len0 * len0; \
len0 = double_lut[ 4 * k ] - col0; \
dist += len1 * len1; \
len1 = double_lut[ 4 * k + 1 ] - col1; \
dist += len2 * len2; \
len2 = double_lut[ 4 * k + 2 ] - col2; \
dist += len3 * len3; \
len3 = double_lut[ 4 * k + 3 ] - col3; \
diff = ( mlib_s32 )( dist * 0.125 ) - min_dist; \
mask = diff >> 31; \
min_dist += diff & mask; \
k_min += ( k - k_min ) & mask; \
} \
dst[ i ] = k_min + offset; \
}
/***************************************************************/
mlib_status mlib_ImageColorTrue2Index(mlib_image *dst,
const mlib_image *src,
const void *colormap)
{
mlib_s32 y, width, height, sstride, dstride, schann;
mlib_colormap *s = (mlib_colormap *)colormap;
mlib_s32 channels;
mlib_type stype, dtype;
MLIB_IMAGE_CHECK(src);
MLIB_IMAGE_CHECK(dst);
MLIB_IMAGE_SIZE_EQUAL(src, dst);
MLIB_IMAGE_HAVE_CHAN(dst, 1);
if (!colormap)
return MLIB_NULLPOINTER;
channels = s->channels;
stype = mlib_ImageGetType(src);
dtype = mlib_ImageGetType(dst);
width = mlib_ImageGetWidth(src);
height = mlib_ImageGetHeight(src);
sstride = mlib_ImageGetStride(src);
dstride = mlib_ImageGetStride(dst);
schann = mlib_ImageGetChannels(src);
if (stype != s->intype || dtype != s->outtype)
return MLIB_FAILURE;
if (channels != schann)
return MLIB_FAILURE;
switch (stype) {
case MLIB_BYTE:
{
mlib_u8 *sdata = mlib_ImageGetData(src);
switch (dtype) {
case MLIB_BYTE:
{
mlib_u8 *ddata = mlib_ImageGetData(dst);
switch (channels) {
case 3:
{
MAIN_COLORTRUE2INDEX_LOOP(U8, U8, 3);
return MLIB_SUCCESS;
}
case 4:
{
MAIN_COLORTRUE2INDEX_LOOP(U8, U8, 4);
return MLIB_SUCCESS;
}
default:
return MLIB_FAILURE;
}
}
case MLIB_SHORT:
{
mlib_s16 *ddata = mlib_ImageGetData(dst);
dstride /= 2;
switch (channels) {
case 3:
{
MAIN_COLORTRUE2INDEX_LOOP(U8, S16, 3);
return MLIB_SUCCESS;
}
case 4:
{
MAIN_COLORTRUE2INDEX_LOOP(U8, S16, 4);
return MLIB_SUCCESS;
}
default:
return MLIB_FAILURE;
}
}
default:
/* Unsupported type of destination image */
return MLIB_FAILURE;
}
}
case MLIB_SHORT:
{
mlib_s16 *sdata = mlib_ImageGetData(src);
sstride /= 2;
switch (dtype) {
case MLIB_BYTE:
{
mlib_u8 *ddata = mlib_ImageGetData(dst);
switch (channels) {
case 3:
{
MAIN_COLORTRUE2INDEX_LOOP(S16, U8, 3);
return MLIB_SUCCESS;
}
case 4:
{
MAIN_COLORTRUE2INDEX_LOOP(S16, U8, 4);
return MLIB_SUCCESS;
}
default:
return MLIB_FAILURE;
}
}
case MLIB_SHORT:
{
mlib_s16 *ddata = mlib_ImageGetData(dst);
dstride /= 2;
switch (channels) {
case 3:
{
MAIN_COLORTRUE2INDEX_LOOP(S16, S16, 3);
return MLIB_SUCCESS;
}
case 4:
{
MAIN_COLORTRUE2INDEX_LOOP(S16, S16, 4);
return MLIB_SUCCESS;
}
default:
return MLIB_FAILURE;
}
}
default:
/* Unsupported type of destination image */
return MLIB_FAILURE;
}
}
default:
return MLIB_FAILURE;
}
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_U8_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
mlib_u32 c0,
mlib_u32 c1,
mlib_u32 c2,
const mlib_u8 **base)
{
mlib_s32 i;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newdistance = FIND_DISTANCE_3(c0, newpalc0, c1, newpalc1, c2, newpalc2, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i])
distance =
mlib_search_quadrant_U8_3(node->contents.quadrants[i], distance,
found_color, c0, c1, c2, base);
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_left_U8_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_u8 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[3][4] = {
{0, 2, 4, 6},
{0, 1, 4, 5},
{0, 1, 2, 3}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance < (position + current_size - c[dir_bit]) * (position + current_size - c[dir_bit])) { /* Search half of quadrant */
for (i = 0; i < 4; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_left_U8_3(node->contents.quadrants[qq],
distance, found_color, c, base,
position, pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_left_U8_3(node->contents.quadrants[i],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
else
/* Here we should check all */
distance =
mlib_search_quadrant_U8_3(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], base);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_right_U8_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_u8 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[3][4] = {
{1, 3, 5, 7},
{2, 3, 6, 7},
{4, 5, 6, 7}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance <= (c[dir_bit] - position - current_size) * (c[dir_bit] - position - current_size)) { /* Search half of quadrant */
for (i = 0; i < 4; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_right_U8_3(node->contents.quadrants[qq],
distance, found_color, c,
base, position + current_size,
pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* Here we should check all */
distance =
mlib_search_quadrant_U8_3(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], base);
else
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_right_U8_3(node->contents.quadrants[i],
distance, found_color, c,
base, position, pass - 1, dir_bit);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_S16_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
mlib_u32 c0,
mlib_u32 c1,
mlib_u32 c2,
const mlib_s16 **base)
{
mlib_s32 i;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_3(c0, newpalc0, c1, newpalc1, c2, newpalc2, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i])
distance =
mlib_search_quadrant_S16_3(node->contents.quadrants[i], distance,
found_color, c0, c1, c2, base);
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_left_S16_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_s16 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[3][4] = {
{0, 2, 4, 6},
{0, 1, 4, 5},
{0, 1, 2, 3}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance < (((position + current_size - c[dir_bit]) * (position + current_size - c[dir_bit])) >> 2)) { /* Search half of quadrant */
for (i = 0; i < 4; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_left_S16_3(node->contents.quadrants[qq],
distance, found_color, c,
base, position, pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_left_S16_3(node->contents.quadrants[i],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
else
/* Here we should check all */
distance =
mlib_search_quadrant_S16_3(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], base);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_right_S16_3(struct lut_node_3 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_s16 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[3][4] = {
{1, 3, 5, 7},
{2, 3, 6, 7},
{4, 5, 6, 7}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance <= (((c[dir_bit] - position - current_size) * (c[dir_bit] - position - current_size)) >> 2)) { /* Search half of quadrant */
for (i = 0; i < 4; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_right_S16_3(node->contents.quadrants[qq],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 8; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_3(c[0], newpalc0, c[1], newpalc1, c[2], newpalc2, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* Here we should check all */
distance =
mlib_search_quadrant_S16_3(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], base);
else
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_right_S16_3(node->contents.
quadrants[i], distance,
found_color, c, base,
position, pass - 1, dir_bit);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_U8_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
mlib_u32 c0,
mlib_u32 c1,
mlib_u32 c2,
mlib_u32 c3,
const mlib_u8 **base)
{
mlib_s32 i;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newpalc3 = base[3][newindex];
newdistance = FIND_DISTANCE_4(c0, newpalc0,
c1, newpalc1, c2, newpalc2, c3, newpalc3, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i])
distance =
mlib_search_quadrant_U8_4(node->contents.quadrants[i], distance,
found_color, c0, c1, c2, c3, base);
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_left_U8_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_u8 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[4][8] = {
{0, 2, 4, 6, 8, 10, 12, 14},
{0, 1, 4, 5, 8, 9, 12, 13},
{0, 1, 2, 3, 8, 9, 10, 11},
{0, 1, 2, 3, 4, 5, 6, 7}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance < (position + current_size - c[dir_bit]) * (position + current_size - c[dir_bit])) { /* Search half of quadrant */
for (i = 0; i < 8; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newpalc3 = base[3][newindex];
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_left_U8_4(node->contents.quadrants[qq],
distance, found_color, c, base,
position, pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newpalc3 = base[3][newindex];
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_left_U8_4(node->contents.quadrants[i],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
else
/* Here we should check all */
distance =
mlib_search_quadrant_U8_4(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], c[3], base);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_right_U8_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_u8 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[4][8] = {
{1, 3, 5, 7, 9, 11, 13, 15},
{2, 3, 6, 7, 10, 11, 14, 15},
{4, 5, 6, 7, 12, 13, 14, 15},
{8, 9, 10, 11, 12, 13, 14, 15}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance <= (c[dir_bit] - position - current_size) * (c[dir_bit] - position - current_size)) { /* Search half of quadrant */
for (i = 0; i < 8; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newpalc3 = base[3][newindex];
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_right_U8_4(node->contents.quadrants[qq],
distance, found_color, c,
base, position + current_size,
pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex];
newpalc1 = base[1][newindex];
newpalc2 = base[2][newindex];
newpalc3 = base[3][newindex];
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 0);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* Here we should check all */
distance =
mlib_search_quadrant_U8_4(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], c[3], base);
else
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_right_U8_4(node->contents.quadrants[i],
distance, found_color, c,
base, position, pass - 1, dir_bit);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_S16_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
mlib_u32 c0,
mlib_u32 c1,
mlib_u32 c2,
mlib_u32 c3,
const mlib_s16 **base)
{
mlib_s32 i;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newpalc3 = base[3][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_4(c0, newpalc0,
c1, newpalc1, c2, newpalc2, c3, newpalc3, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i])
distance =
mlib_search_quadrant_S16_4(node->contents.quadrants[i], distance,
found_color, c0, c1, c2, c3, base);
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_left_S16_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_s16 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[4][8] = {
{0, 2, 4, 6, 8, 10, 12, 14},
{0, 1, 4, 5, 8, 9, 12, 13},
{0, 1, 2, 3, 8, 9, 10, 11},
{0, 1, 2, 3, 4, 5, 6, 7}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance < (((position + current_size - c[dir_bit]) * (position + current_size - c[dir_bit])) >> 2)) { /* Search half of quadrant */
for (i = 0; i < 8; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newpalc3 = base[3][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_left_S16_4(node->contents.quadrants[qq],
distance, found_color, c,
base, position, pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newpalc3 = base[3][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_left_S16_4(node->contents.quadrants[i],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
else
/* Here we should check all */
distance =
mlib_search_quadrant_S16_4(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], c[3], base);
}
}
}
return distance;
}
/***************************************************************/
mlib_u32 mlib_search_quadrant_part_to_right_S16_4(struct lut_node_4 *node,
mlib_u32 distance,
mlib_s32 *found_color,
const mlib_u32 *c,
const mlib_s16 **base,
mlib_u32 position,
mlib_s32 pass,
mlib_s32 dir_bit)
{
mlib_u32 current_size = 1 << pass;
mlib_s32 i;
static mlib_s32 opposite_quadrants[4][8] = {
{1, 3, 5, 7, 9, 11, 13, 15},
{2, 3, 6, 7, 10, 11, 14, 15},
{4, 5, 6, 7, 12, 13, 14, 15},
{8, 9, 10, 11, 12, 13, 14, 15}
};
/* Search only quadrant's half untill it is necessary to check the
whole quadrant */
if (distance <= (((c[dir_bit] - position - current_size) * (c[dir_bit] - position - current_size)) >> 2)) { /* Search half of quadrant */
for (i = 0; i < 8; i++) {
mlib_s32 qq = opposite_quadrants[dir_bit][i];
if (node->tag & (1 << qq)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[qq];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newpalc3 = base[3][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[qq])
distance =
mlib_search_quadrant_part_to_right_S16_4(node->contents.quadrants[qq],
distance, found_color, c,
base,
position + current_size,
pass - 1, dir_bit);
}
}
else { /* Search whole quadrant */
mlib_s32 mask = 1 << dir_bit;
for (i = 0; i < 16; i++) {
if (node->tag & (1 << i)) {
/* Here is alone color cell. Check the distance */
mlib_s32 newindex = node->contents.index[i];
mlib_u32 newpalc0, newpalc1, newpalc2, newpalc3;
mlib_u32 newdistance;
newpalc0 = base[0][newindex] - MLIB_S16_MIN;
newpalc1 = base[1][newindex] - MLIB_S16_MIN;
newpalc2 = base[2][newindex] - MLIB_S16_MIN;
newpalc3 = base[3][newindex] - MLIB_S16_MIN;
newdistance = FIND_DISTANCE_4(c[0], newpalc0,
c[1], newpalc1, c[2], newpalc2, c[3], newpalc3, 2);
if (distance > newdistance) {
*found_color = newindex;
distance = newdistance;
}
}
else if (node->contents.quadrants[i]) {
if (i & mask)
/* Here we should check all */
distance =
mlib_search_quadrant_S16_4(node->contents.quadrants[i], distance,
found_color, c[0], c[1], c[2], c[3], base);
else
/* This quadrant may require partial checking */
distance =
mlib_search_quadrant_part_to_right_S16_4(node->contents.
quadrants[i], distance,
found_color, c, base,
position, pass - 1, dir_bit);
}
}
}
return distance;
}
/***************************************************************/
#define TAB_SIZE_mlib_u8 256
#define TAB_SIZE_mlib_s16 1024
#define SRC_mlib_u8(i) src[i]
#define SRC_mlib_s16(i) (((mlib_u16*)src)[i] >> 6)
/***************************************************************/
#define DIMENSIONS_SEARCH_3(STYPE, DTYPE, STEP) \
{ \
DTYPE *tab0 = ((mlib_colormap *)state)->table; \
DTYPE *tab1 = tab0 + TAB_SIZE_##STYPE; \
DTYPE *tab2 = tab1 + TAB_SIZE_##STYPE; \
mlib_s32 i; \
\
for (i = 0; i < length; i++) { \
dst[i] = tab0[SRC_##STYPE(0)] + tab1[SRC_##STYPE(1)] + \
tab2[SRC_##STYPE(2)]; \
src += STEP; \
} \
}
/***************************************************************/
#define DIMENSIONS_SEARCH_4(STYPE, DTYPE) \
{ \
DTYPE *tab0 = ((mlib_colormap *)state)->table; \
DTYPE *tab1 = tab0 + TAB_SIZE_##STYPE; \
DTYPE *tab2 = tab1 + TAB_SIZE_##STYPE; \
DTYPE *tab3 = tab2 + TAB_SIZE_##STYPE; \
mlib_s32 i; \
\
for (i = 0; i < length; i++) { \
dst[i] = tab0[SRC_##STYPE(0)] + tab1[SRC_##STYPE(1)] + \
tab2[SRC_##STYPE(2)] + tab3[SRC_##STYPE(3)]; \
src += 4; \
} \
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_U8_3(const mlib_u8 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_BYTE_COLORS_3CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_3(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 0, 3, 0);
}
break;
#endif /* LUT_BYTE_COLORS_3CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_U8_3_SEARCH(mlib_u8, 0, 3);
}
break;
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_3;
#else
FIND_NEAREST_U8_3_C(0, 3);
#endif
}
break;
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_3(mlib_u8, mlib_u8, 3)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_U8_3_in_4(const mlib_u8 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_BYTE_COLORS_3CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_3(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 1, 4, 0);
break;
}
#endif /* LUT_BYTE_COLORS_3CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_U8_3_SEARCH(mlib_u8, 1, 4);
break;
}
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_3_IN4;
#else
FIND_NEAREST_U8_3_C(1, 4);
#endif
break;
}
case LUT_COLOR_DIMENSIONS:
src++;
DIMENSIONS_SEARCH_3(mlib_u8, mlib_u8, 4)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_U8_4(const mlib_u8 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_BYTE_COLORS_4CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_4(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 0);
break;
}
#endif /* LUT_BYTE_COLORS_4CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_U8_4_SEARCH(mlib_u8);
break;
}
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_4;
#else
FIND_NEAREST_U8_4_C;
#endif
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_4(mlib_u8, mlib_u8)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_S16_3(const mlib_u8 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_3(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 0, 3, 0);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_U8_3_SEARCH(mlib_u8, 0, 3);
break;
}
case 2:
{
COLOR_CUBE_U8_3_SEARCH(mlib_s16, 0, 3);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_3;
#else
FIND_NEAREST_U8_3_C(0, 3);
#endif
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_3(mlib_u8, mlib_s16, 3)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_S16_3_in_4(const mlib_u8 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_3(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 1, 4, 0);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_U8_3_SEARCH(mlib_u8, 1, 4);
break;
}
case 2:
{
COLOR_CUBE_U8_3_SEARCH(mlib_s16, 1, 4);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_3_IN4;
#else
FIND_NEAREST_U8_3_C(1, 4);
#endif
break;
}
case LUT_COLOR_DIMENSIONS:
src++;
DIMENSIONS_SEARCH_3(mlib_u8, mlib_s16, 4)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_S16_4(const mlib_u8 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_4(U8, mlib_u8, 8, (MLIB_U8_MAX + 1), 0, 0);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_U8_4_SEARCH(mlib_u8);
break;
}
case 2:
{
COLOR_CUBE_U8_4_SEARCH(mlib_s16);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
#ifdef USE_VIS_CODE
FIND_NEAREST_U8_4;
#else
FIND_NEAREST_U8_4_C;
#endif
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_4(mlib_u8, mlib_s16)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_S16_3(const mlib_s16 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_3(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 0, 3, 2);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_S16_3_SEARCH(mlib_u8, 0, 3);
break;
}
case 2:
{
COLOR_CUBE_S16_3_SEARCH(mlib_s16, 0, 3);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_3(0, 3);
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_3(mlib_s16, mlib_s16, 3)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_S16_3_in_4(const mlib_s16 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_3(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 1, 4, 2);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_S16_3_SEARCH(mlib_u8, 1, 4);
break;
}
case 2:
{
COLOR_CUBE_S16_3_SEARCH(mlib_s16, 1, 4);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_3(1, 4);
break;
}
case LUT_COLOR_DIMENSIONS:
src++;
DIMENSIONS_SEARCH_3(mlib_s16, mlib_s16, 4)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_S16_4(const mlib_s16 *src,
mlib_s16 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
mlib_s32 bits = s->bits;
switch (s->method) {
case LUT_BINARY_TREE_SEARCH:
{
BINARY_TREE_SEARCH_4(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 2);
break;
}
case LUT_COLOR_CUBE_SEARCH:
{
switch (s->indexsize) {
case 1:
{
COLOR_CUBE_S16_4_SEARCH(mlib_u8);
break;
}
case 2:
{
COLOR_CUBE_S16_4_SEARCH(mlib_s16);
break;
}
}
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_4;
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_4(mlib_s16, mlib_s16)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_U8_3(const mlib_s16 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_SHORT_COLORS_3CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_3(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 0, 3, 2);
break;
}
#endif /* LUT_SHORT_COLORS_3CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_S16_3_SEARCH(mlib_u8, 0, 3);
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_3(0, 3);
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_3(mlib_s16, mlib_u8, 3)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_U8_3_in_4(const mlib_s16 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_SHORT_COLORS_3CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_3(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 1, 4, 2);
break;
}
#endif /* LUT_SHORT_COLORS_3CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_S16_3_SEARCH(mlib_u8, 1, 4);
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_3(1, 4);
break;
}
case LUT_COLOR_DIMENSIONS:
src++;
DIMENSIONS_SEARCH_3(mlib_s16, mlib_u8, 4)
break;
}
}
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_S16_U8_4(const mlib_s16 *src,
mlib_u8 *dst,
mlib_s32 length,
const void *state)
{
mlib_colormap *s = (mlib_colormap *)state;
switch (s->method) {
#if LUT_SHORT_COLORS_4CHANNELS <= 256
case LUT_BINARY_TREE_SEARCH:
{
mlib_s32 bits = s->bits;
BINARY_TREE_SEARCH_4(S16, mlib_s16, 16, ((MLIB_S16_MAX + 1) * 2),
MLIB_S16_MIN, 2);
break;
}
#endif /* LUT_SHORT_COLORS_4CHANNELS <= 256 */
case LUT_COLOR_CUBE_SEARCH:
{
COLOR_CUBE_S16_4_SEARCH(mlib_u8);
break;
}
case LUT_STUPID_SEARCH:
{
FIND_NEAREST_S16_4;
break;
}
case LUT_COLOR_DIMENSIONS:
DIMENSIONS_SEARCH_4(mlib_s16, mlib_u8)
break;
}
}
/***************************************************************/
#ifndef VIS
void mlib_c_ImageThresh1_U81_1B(void *psrc,
void *pdst,
mlib_s32 src_stride,
mlib_s32 dst_stride,
mlib_s32 width,
mlib_s32 height,
void *thresh,
void *ghigh,
void *glow,
mlib_s32 dbit_off);
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_BIT_1(const mlib_u8 *src,
mlib_u8 *dst,
mlib_s32 bit_offset,
mlib_s32 length,
const void *state)
{
mlib_u8 *lut = ((mlib_colormap *)state)->table;
mlib_s32 thresh[1];
mlib_s32 ghigh[1];
mlib_s32 glow[1];
thresh[0] = lut[2];
glow[0] = lut[0] - lut[1];
ghigh[0] = lut[1] - lut[0];
mlib_c_ImageThresh1_U81_1B((void*)src, dst, 0, 0, length, 1,
thresh, ghigh, glow, bit_offset);
}
#else
/***************************************************************/
void mlib_v_ImageThresh1B_U8_1(const mlib_u8 *src,
mlib_s32 slb,
mlib_u8 *dst,
mlib_s32 dlb,
mlib_s32 xsize,
mlib_s32 ysize,
mlib_s32 dbit_off,
const mlib_s32 *th,
mlib_s32 hc,
mlib_s32 lc);
/***************************************************************/
void mlib_ImageColorTrue2IndexLine_U8_BIT_1(const mlib_u8 *src,
mlib_u8 *dst,
mlib_s32 bit_offset,
mlib_s32 length,
const void *state)
{
mlib_u8 *lut = ((mlib_colormap *)state)->table;
mlib_s32 thresh[4];
mlib_s32 ghigh[1];
mlib_s32 glow[1];
thresh[0] = thresh[1] = thresh[2] = thresh[3] = lut[2];
glow[0] = (lut[1] < lut[0]) ? 0xFF : 0;
ghigh[0] = (lut[1] < lut[0]) ? 0 : 0xFF;
mlib_v_ImageThresh1B_U8_1((void*)src, 0, dst, 0, length, 1,
bit_offset, thresh, ghigh[0], glow[0]);
}
/***************************************************************/
#endif