629 lines
22 KiB
C
629 lines
22 KiB
C
/* *****************************************************************************
|
|
*
|
|
* Copyright (c) 2007-2016 Alexis Naveros.
|
|
* Portions developed under contract to the SURVICE Engineering Company.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public License
|
|
* version 2.1 as published by the Free Software Foundation.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this file; see the file named COPYING for more
|
|
* information.
|
|
*
|
|
* *****************************************************************************
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
|
|
#include "cpusimd.h"
|
|
|
|
#include "img.h"
|
|
|
|
|
|
#ifndef ADDRESS
|
|
#define ADDRESS(p,o) ((void *)(((char *)p)+(o)))
|
|
#endif
|
|
|
|
|
|
////
|
|
|
|
|
|
void imgCopyRect( imgImage *image, int dstx, int dsty, int srcx, int srcy, int sizex, int sizey )
|
|
{
|
|
int y;
|
|
void *dst, *src;
|
|
src = ADDRESS( image->data, ( srcx * image->format.bytesperpixel ) + ( srcy * image->format.bytesperline ) );
|
|
dst = ADDRESS( image->data, ( dstx * image->format.bytesperpixel ) + ( dsty * image->format.bytesperline ) );
|
|
for( y = 0 ; y < sizey ; y++ )
|
|
{
|
|
memcpy( dst, src, sizex * image->format.bytesperpixel );
|
|
src = ADDRESS( src, image->format.bytesperline );
|
|
dst = ADDRESS( dst, image->format.bytesperline );
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
#if CPU_SSE2_SUPPORT
|
|
static const uint16_t CPU_ALIGN16 imgBlendRgbMask[8] = { 0xffff, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff, 0x0000 };
|
|
static const uint8_t CPU_ALIGN16 imgBlendAlphaTestMask[16] = { 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0xff };
|
|
static const uint16_t CPU_ALIGN16 imgBlendRoundBias[8] = { 128, 128, 128, 128, 128, 128, 128, 128 };
|
|
#if CPU_SSSE3_SUPPORT
|
|
static const uint8_t CPU_ALIGN16 imgBlendShufMask[16] = { 6,7,6,7,6,7,6,7, 14,15,14,15,14,15,14,15 };
|
|
#endif
|
|
#endif
|
|
|
|
static void imgBlendImageRgba2Rgba( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage )
|
|
{
|
|
int x, y;
|
|
#if CPU_SSE2_SUPPORT
|
|
int row4size;
|
|
__m128i vsrc01, vsrc23, vdst01, vdst23, vblend01, vblend23;
|
|
__m128i vzero, v255, vrgbmask, valphatest, vroundbias;
|
|
#if CPU_SSSE3_SUPPORT
|
|
__m128i vshufmask;
|
|
#endif
|
|
#else
|
|
int32_t dstr, dstg, dstb, dsta;
|
|
int32_t srcr, srcg, srcb, srca;
|
|
#endif
|
|
unsigned char *src, *srcrow, *dstrow;
|
|
uint32_t *dst;
|
|
|
|
/* TODO: Other function to clamp copy area? */
|
|
|
|
#if CPU_SSE2_SUPPORT
|
|
row4size = srcimage->format.width & ~3;
|
|
vzero = _mm_setzero_si128();
|
|
v255 = _mm_set1_epi16( 255 );
|
|
vrgbmask = _mm_load_si128( (void *)imgBlendRgbMask );
|
|
valphatest = _mm_load_si128( (void *)imgBlendAlphaTestMask );
|
|
vroundbias = _mm_load_si128( (void *)imgBlendRoundBias );
|
|
#if CPU_SSSE3_SUPPORT
|
|
vshufmask = _mm_load_si128( (void *)imgBlendShufMask );
|
|
#endif
|
|
#endif
|
|
|
|
src = srcimage->data;
|
|
dst = ADDRESS( dstimage->data, ( dstx * 4 ) + ( dsty * dstimage->format.bytesperline ) );
|
|
for( y = 0 ; y < srcimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = (unsigned char *)dst;
|
|
|
|
#if CPU_SSE2_SUPPORT
|
|
for( x = 0 ; x < row4size ; x += 4, srcrow += 16, dstrow += 16 )
|
|
{
|
|
/* r0g0b0a0,r1g1b1a1,r2g2b2a2,r3g3b3a3 */
|
|
vsrc23 = _mm_loadu_si128( (void *)srcrow );
|
|
if( _mm_movemask_ps( _mm_castsi128_ps( _mm_cmpeq_epi32( _mm_and_si128( valphatest, vsrc23 ), vzero ) ) ) == 0xf )
|
|
continue;
|
|
vdst23 = _mm_loadu_si128( (void *)dstrow );
|
|
/* r0__g0__b0__a0__, r1__g1__b1__a1__ */
|
|
vsrc01 = _mm_unpacklo_epi8( vsrc23, vzero );
|
|
vdst01 = _mm_unpacklo_epi8( vdst23, vzero );
|
|
/* r2__g2__b2__a2__, r3__g3__b3__a3__ */
|
|
vsrc23 = _mm_unpackhi_epi8( vsrc23, vzero );
|
|
vdst23 = _mm_unpackhi_epi8( vdst23, vzero );
|
|
#if CPU_SSSE3_SUPPORT
|
|
/* __a0__a0__a0__a0, __a1__a1__a1__a1 */
|
|
vblend01 = _mm_shuffle_epi8( vsrc01, vshufmask );
|
|
/* __a2__a2__a2__a2, __a3__a3__a3__a3 */
|
|
vblend23 = _mm_shuffle_epi8( vsrc23, vshufmask );
|
|
#else
|
|
vblend01 = _mm_shufflelo_epi16( vsrc01, 0xff );
|
|
vblend01 = _mm_shufflehi_epi16( vblend01, 0xff );
|
|
vblend23 = _mm_shufflelo_epi16( vsrc23, 0xff );
|
|
vblend23 = _mm_shufflehi_epi16( vblend23, 0xff );
|
|
#endif
|
|
vdst01 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst01, _mm_sub_epi16( v255, _mm_and_si128( vblend01, vrgbmask ) ) ), _mm_mullo_epi16( vsrc01, vblend01 ) ), vroundbias );
|
|
vdst23 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst23, _mm_sub_epi16( v255, _mm_and_si128( vblend23, vrgbmask ) ) ), _mm_mullo_epi16( vsrc23, vblend23 ) ), vroundbias );
|
|
/* Correction to divide by 255 instead of 256 */
|
|
vdst01 = _mm_srli_epi16( _mm_adds_epu16( vdst01, _mm_srli_epi16( vdst01, 8 ) ), 8 );
|
|
vdst23 = _mm_srli_epi16( _mm_adds_epu16( vdst23, _mm_srli_epi16( vdst23, 8 ) ), 8 );
|
|
/* Combine interleaved and store */
|
|
_mm_storeu_si128( (void *)dstrow, _mm_packus_epi16( vdst01, vdst23 ) );
|
|
}
|
|
for( ; x < srcimage->format.width ; x++, srcrow += 4, dstrow += 4 )
|
|
{
|
|
if( !( srcrow[3] ) )
|
|
continue;
|
|
vsrc01 = _mm_castps_si128( _mm_load_ss( (void *)srcrow ) );
|
|
vdst01 = _mm_castps_si128( _mm_load_ss( (void *)dstrow ) );
|
|
vsrc01 = _mm_unpacklo_epi8( vsrc01, vzero );
|
|
vdst01 = _mm_unpacklo_epi8( vdst01, vzero );
|
|
#if CPU_SSSE3_SUPPORT
|
|
vblend01 = _mm_shuffle_epi8( vsrc01, vshufmask );
|
|
#else
|
|
vblend01 = _mm_shufflelo_epi16( vsrc01, 0xff );
|
|
vblend01 = _mm_shufflehi_epi16( vblend01, 0xff );
|
|
#endif
|
|
vdst01 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst01, _mm_sub_epi16( v255, _mm_and_si128( vblend01, vrgbmask ) ) ), _mm_mullo_epi16( vsrc01, vblend01 ) ), vroundbias );
|
|
/* Correction to divide by 255 instead of 256 */
|
|
vdst01 = _mm_srli_epi16( _mm_adds_epu16( vdst01, _mm_srli_epi16( vdst01, 8 ) ), 8 );
|
|
_mm_store_ss( (void *)dstrow, _mm_castsi128_ps( _mm_packus_epi16( vdst01, vdst01 ) ) );
|
|
}
|
|
#else
|
|
for( x = 0 ; x < srcimage->format.width ; x++, srcrow += 4, dstrow += 4 )
|
|
{
|
|
if( !( srcrow[3] ) )
|
|
continue;
|
|
srcr = (int32_t)srcrow[0];
|
|
srcg = (int32_t)srcrow[1];
|
|
srcb = (int32_t)srcrow[2];
|
|
srca = (int32_t)srcrow[3];
|
|
dstr = (int32_t)dstrow[0];
|
|
dstg = (int32_t)dstrow[1];
|
|
dstb = (int32_t)dstrow[2];
|
|
dsta = (int32_t)dstrow[3];
|
|
dstr = ( ( dstr << 8 ) - dstr + ( srca * ( srcr - dstr ) ) + 128 );
|
|
dstg = ( ( dstg << 8 ) - dstg + ( srca * ( srcg - dstg ) ) + 128 );
|
|
dstb = ( ( dstb << 8 ) - dstb + ( srca * ( srcb - dstb ) ) + 128 );
|
|
dsta = ( ( dsta << 8 ) - dsta + ( srca * srca ) + 128 );
|
|
dstr = ( dstr + ( dstr >> 8 ) ) >> 8;
|
|
dstg = ( dstg + ( dstg >> 8 ) ) >> 8;
|
|
dstb = ( dstb + ( dstb >> 8 ) ) >> 8;
|
|
dsta = ( dsta + ( dsta >> 8 ) ) >> 8;
|
|
if( dsta > 255 )
|
|
dsta = 255;
|
|
dstrow[0] = (unsigned char)dstr;
|
|
dstrow[1] = (unsigned char)dstg;
|
|
dstrow[2] = (unsigned char)dstb;
|
|
dstrow[3] = (unsigned char)dsta;
|
|
}
|
|
#endif
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void imgBlendImageRgba2Rgbx( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage )
|
|
{
|
|
int x, y;
|
|
#if CPU_SSE2_SUPPORT
|
|
int row4size;
|
|
__m128i vsrc01, vsrc23, vdst01, vdst23, vblend01, vblend23;
|
|
__m128i vzero, v255, valphatest, vroundbias;
|
|
#if CPU_SSSE3_SUPPORT
|
|
__m128i vshufmask;
|
|
#endif
|
|
#else
|
|
int32_t dstr, dstg, dstb;
|
|
int32_t srcr, srcg, srcb, srca;
|
|
#endif
|
|
unsigned char *src, *srcrow, *dstrow;
|
|
uint32_t *dst;
|
|
|
|
/* TODO: Other function to clamp copy area? */
|
|
|
|
#if CPU_SSE2_SUPPORT
|
|
row4size = srcimage->format.width & ~3;
|
|
vzero = _mm_setzero_si128();
|
|
v255 = _mm_set1_epi16( 255 );
|
|
valphatest = _mm_load_si128( (void *)imgBlendAlphaTestMask );
|
|
vroundbias = _mm_load_si128( (void *)imgBlendRoundBias );
|
|
#if CPU_SSSE3_SUPPORT
|
|
vshufmask = _mm_load_si128( (void *)imgBlendShufMask );
|
|
#endif
|
|
#endif
|
|
|
|
src = srcimage->data;
|
|
dst = ADDRESS( dstimage->data, ( dstx * 4 ) + ( dsty * dstimage->format.bytesperline ) );
|
|
for( y = 0 ; y < srcimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = (unsigned char *)dst;
|
|
|
|
#if CPU_SSE2_SUPPORT
|
|
for( x = 0 ; x < row4size ; x += 4, srcrow += 16, dstrow += 16 )
|
|
{
|
|
/* r0g0b0a0,r1g1b1a1,r2g2b2a2,r3g3b3a3 */
|
|
vsrc23 = _mm_loadu_si128( (void *)srcrow );
|
|
if( _mm_movemask_ps( _mm_castsi128_ps( _mm_cmpeq_epi32( _mm_and_si128( valphatest, vsrc23 ), vzero ) ) ) == 0xf )
|
|
continue;
|
|
vdst23 = _mm_loadu_si128( (void *)dstrow );
|
|
/* r0__g0__b0__a0__, r1__g1__b1__a1__ */
|
|
vsrc01 = _mm_unpacklo_epi8( vsrc23, vzero );
|
|
vdst01 = _mm_unpacklo_epi8( vdst23, vzero );
|
|
/* r2__g2__b2__a2__, r3__g3__b3__a3__ */
|
|
vsrc23 = _mm_unpackhi_epi8( vsrc23, vzero );
|
|
vdst23 = _mm_unpackhi_epi8( vdst23, vzero );
|
|
#if CPU_SSSE3_SUPPORT
|
|
/* __a0__a0__a0__a0, __a1__a1__a1__a1 */
|
|
vblend01 = _mm_shuffle_epi8( vsrc01, vshufmask );
|
|
/* __a2__a2__a2__a2, __a3__a3__a3__a3 */
|
|
vblend23 = _mm_shuffle_epi8( vsrc23, vshufmask );
|
|
#else
|
|
vblend01 = _mm_shufflelo_epi16( vsrc01, 0xff );
|
|
vblend01 = _mm_shufflehi_epi16( vblend01, 0xff );
|
|
vblend23 = _mm_shufflelo_epi16( vsrc23, 0xff );
|
|
vblend23 = _mm_shufflehi_epi16( vblend23, 0xff );
|
|
#endif
|
|
vdst01 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst01, _mm_sub_epi16( v255, vblend01 ) ), _mm_mullo_epi16( vsrc01, vblend01 ) ), vroundbias );
|
|
vdst23 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst23, _mm_sub_epi16( v255, vblend23 ) ), _mm_mullo_epi16( vsrc23, vblend23 ) ), vroundbias );
|
|
/* Correction to divide by 255 instead of 256 */
|
|
vdst01 = _mm_srli_epi16( _mm_adds_epu16( vdst01, _mm_srli_epi16( vdst01, 8 ) ), 8 );
|
|
vdst23 = _mm_srli_epi16( _mm_adds_epu16( vdst23, _mm_srli_epi16( vdst23, 8 ) ), 8 );
|
|
/* Combine interleaved and store */
|
|
_mm_storeu_si128( (void *)dstrow, _mm_or_si128( _mm_packus_epi16( vdst01, vdst23 ), valphatest ) );
|
|
}
|
|
for( ; x < srcimage->format.width ; x++, srcrow += 4, dstrow += 4 )
|
|
{
|
|
if( !( srcrow[3] ) )
|
|
continue;
|
|
vsrc01 = _mm_castps_si128( _mm_load_ss( (void *)srcrow ) );
|
|
vdst01 = _mm_castps_si128( _mm_load_ss( (void *)dstrow ) );
|
|
vsrc01 = _mm_unpacklo_epi8( vsrc01, vzero );
|
|
vdst01 = _mm_unpacklo_epi8( vdst01, vzero );
|
|
#if CPU_SSSE3_SUPPORT
|
|
vblend01 = _mm_shuffle_epi8( vsrc01, vshufmask );
|
|
#else
|
|
vblend01 = _mm_shufflelo_epi16( vsrc01, 0xff );
|
|
vblend01 = _mm_shufflehi_epi16( vblend01, 0xff );
|
|
#endif
|
|
vdst01 = _mm_adds_epu16( _mm_adds_epu16( _mm_mullo_epi16( vdst01, _mm_sub_epi16( v255, vblend01 ) ), _mm_mullo_epi16( vsrc01, vblend01 ) ), vroundbias );
|
|
/* Correction to divide by 255 instead of 256 */
|
|
vdst01 = _mm_srli_epi16( _mm_adds_epu16( vdst01, _mm_srli_epi16( vdst01, 8 ) ), 8 );
|
|
_mm_store_ss( (void *)dstrow, _mm_castsi128_ps( _mm_or_si128( _mm_packus_epi16( vdst01, vdst01 ), valphatest ) ) );
|
|
}
|
|
#else
|
|
for( x = 0 ; x < srcimage->format.width ; x++, srcrow += 4, dstrow += 4 )
|
|
{
|
|
if( !( srcrow[3] ) )
|
|
continue;
|
|
srcr = (int32_t)srcrow[0];
|
|
srcg = (int32_t)srcrow[1];
|
|
srcb = (int32_t)srcrow[2];
|
|
srca = (int32_t)srcrow[3];
|
|
dstr = (int32_t)dstrow[0];
|
|
dstg = (int32_t)dstrow[1];
|
|
dstb = (int32_t)dstrow[2];
|
|
dstr = ( ( dstr << 8 ) - dstr + ( srca * ( srcr - dstr ) ) + 128 );
|
|
dstg = ( ( dstg << 8 ) - dstg + ( srca * ( srcg - dstg ) ) + 128 );
|
|
dstb = ( ( dstb << 8 ) - dstb + ( srca * ( srcb - dstb ) ) + 128 );
|
|
dstr = ( dstr + ( dstr >> 8 ) ) >> 8;
|
|
dstg = ( dstg + ( dstg >> 8 ) ) >> 8;
|
|
dstb = ( dstb + ( dstb >> 8 ) ) >> 8;
|
|
dstrow[0] = (unsigned char)dstr;
|
|
dstrow[1] = (unsigned char)dstg;
|
|
dstrow[2] = (unsigned char)dstb;
|
|
dstrow[3] = (unsigned char)255;
|
|
}
|
|
#endif
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void imgBlendImageRgba2Rgb( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage )
|
|
{
|
|
int x, y;
|
|
int32_t dstr, dstg, dstb;
|
|
int32_t srcr, srcg, srcb, srca;
|
|
unsigned char *src, *srcrow, *dstrow;
|
|
uint32_t *dst;
|
|
|
|
/* TODO: Other function to clamp copy area? */
|
|
|
|
src = srcimage->data;
|
|
dst = ADDRESS( dstimage->data, ( dstx * 3 ) + ( dsty * dstimage->format.bytesperline ) );
|
|
for( y = 0 ; y < srcimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = (unsigned char *)dst;
|
|
for( x = 0 ; x < srcimage->format.width ; x++, srcrow += 4, dstrow += 3 )
|
|
{
|
|
if( !( srcrow[3] ) )
|
|
continue;
|
|
srcr = (int32_t)srcrow[0];
|
|
srcg = (int32_t)srcrow[1];
|
|
srcb = (int32_t)srcrow[2];
|
|
srca = (int32_t)srcrow[3];
|
|
dstr = (int32_t)dstrow[0];
|
|
dstg = (int32_t)dstrow[1];
|
|
dstb = (int32_t)dstrow[2];
|
|
dstr = ( ( dstr << 8 ) - dstr + ( srca * ( srcr - dstr ) ) + 128 );
|
|
dstg = ( ( dstg << 8 ) - dstg + ( srca * ( srcg - dstg ) ) + 128 );
|
|
dstb = ( ( dstb << 8 ) - dstb + ( srca * ( srcb - dstb ) ) + 128 );
|
|
dstr = ( dstr + ( dstr >> 8 ) ) >> 8;
|
|
dstg = ( dstg + ( dstg >> 8 ) ) >> 8;
|
|
dstb = ( dstb + ( dstb >> 8 ) ) >> 8;
|
|
dstrow[0] = (unsigned char)dstr;
|
|
dstrow[1] = (unsigned char)dstg;
|
|
dstrow[2] = (unsigned char)dstb;
|
|
}
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void (*imgBlendGetFunction( imgImage *dstimage, imgImage *srcimage ))( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage )
|
|
{
|
|
void (*blendfunc)( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage );
|
|
blendfunc = 0;
|
|
if( srcimage->format.bytesperpixel == 4 )
|
|
{
|
|
if( dstimage->format.bytesperpixel == 4 )
|
|
{
|
|
if( ( dstimage->format.type == IMG_FORMAT_TYPE_RGBA32 ) || ( dstimage->format.type == IMG_FORMAT_TYPE_BGRA32 ) )
|
|
blendfunc = imgBlendImageRgba2Rgba;
|
|
else
|
|
blendfunc = imgBlendImageRgba2Rgbx;
|
|
}
|
|
else if( dstimage->format.bytesperpixel == 3 )
|
|
blendfunc = imgBlendImageRgba2Rgb;
|
|
}
|
|
return blendfunc;
|
|
}
|
|
|
|
|
|
int imgBlendImage( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage )
|
|
{
|
|
void (*blendfunc)( imgImage *dstimage, int dstx, int dsty, imgImage *srcimage );
|
|
blendfunc = imgBlendGetFunction( dstimage, srcimage );
|
|
if( blendfunc )
|
|
{
|
|
blendfunc( dstimage, dstx, dsty, srcimage );
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
////
|
|
|
|
|
|
void imgAllocCopy( imgImage *dstimage, imgImage *srcimage )
|
|
{
|
|
dstimage->format = srcimage->format;
|
|
dstimage->data = malloc( srcimage->format.height * srcimage->format.bytesperline );
|
|
memcpy( dstimage->data, srcimage->data, srcimage->format.height * srcimage->format.bytesperline );
|
|
return;
|
|
}
|
|
|
|
|
|
void imgAllocCopyExtendBorder( imgImage *dstimage, imgImage *srcimage, int extendsize )
|
|
{
|
|
int y;
|
|
void *dst, *src, *dstrow;
|
|
|
|
dstimage->format.width = srcimage->format.width + ( extendsize << 1 );
|
|
dstimage->format.height = srcimage->format.height + ( extendsize << 1 );
|
|
dstimage->format.type = srcimage->format.type;
|
|
dstimage->format.bytesperpixel = srcimage->format.bytesperpixel;
|
|
dstimage->format.bytesperline = dstimage->format.width * dstimage->format.bytesperpixel;
|
|
dstimage->data = malloc( dstimage->format.height * dstimage->format.bytesperline );
|
|
|
|
src = srcimage->data;
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < extendsize ; y++ )
|
|
{
|
|
memset( dst, 0, dstimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
for( y = 0 ; y < srcimage->format.height ; y++ )
|
|
{
|
|
dstrow = dst;
|
|
memset( dstrow, 0, extendsize * dstimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, extendsize * dstimage->format.bytesperpixel );
|
|
memcpy( dstrow, src, srcimage->format.width * dstimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, srcimage->format.width * dstimage->format.bytesperpixel );
|
|
memset( dstrow, 0, extendsize * dstimage->format.bytesperpixel );
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
for( y = 0 ; y < extendsize ; y++ )
|
|
{
|
|
memset( dst, 0, dstimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void imgAllocExtractChannel( imgImage *dstimage, imgImage *srcimage, int channelindex )
|
|
{
|
|
int x, y;
|
|
unsigned char *dst, *src, *srcrow;
|
|
|
|
dstimage->format.width = srcimage->format.width;
|
|
dstimage->format.height = srcimage->format.height;
|
|
dstimage->format.type = IMG_FORMAT_TYPE_GRAYSCALE;
|
|
dstimage->format.bytesperpixel = 1;
|
|
dstimage->format.bytesperline = dstimage->format.width * dstimage->format.bytesperpixel;
|
|
dstimage->data = malloc( dstimage->format.height * dstimage->format.bytesperline );
|
|
|
|
src = ADDRESS( srcimage->data, channelindex );
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < dstimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
for( x = 0 ; x < dstimage->format.width ; x++ )
|
|
{
|
|
dst[x] = *srcrow;
|
|
srcrow = ADDRESS( srcrow, srcimage->format.bytesperpixel );
|
|
}
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void imgAllocExtractChannelExtendBorder( imgImage *dstimage, imgImage *srcimage, int channelindex, int extendsize )
|
|
{
|
|
int x, y;
|
|
unsigned char *src, *dst, *srcrow, *dstrow;
|
|
|
|
dstimage->format.width = srcimage->format.width + ( extendsize << 1 );
|
|
dstimage->format.height = srcimage->format.height + ( extendsize << 1 );
|
|
dstimage->format.type = IMG_FORMAT_TYPE_GRAYSCALE;
|
|
dstimage->format.bytesperpixel = 1;
|
|
dstimage->format.bytesperline = dstimage->format.width * dstimage->format.bytesperpixel;
|
|
dstimage->data = malloc( dstimage->format.height * dstimage->format.bytesperline );
|
|
|
|
src = ADDRESS( srcimage->data, channelindex );
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < extendsize ; y++ )
|
|
{
|
|
memset( dst, 0, dstimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
for( y = 0 ; y < srcimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = dst;
|
|
memset( dstrow, 0, extendsize * dstimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, extendsize * dstimage->format.bytesperpixel );
|
|
for( x = 0 ; x < srcimage->format.width ; x++ )
|
|
{
|
|
dstrow[x] = *srcrow;
|
|
srcrow = ADDRESS( srcrow, srcimage->format.bytesperpixel );
|
|
}
|
|
dstrow = ADDRESS( dstrow, srcimage->format.width * dstimage->format.bytesperpixel );
|
|
memset( dstrow, 0, extendsize * dstimage->format.bytesperpixel );
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
for( y = 0 ; y < extendsize ; y++ )
|
|
{
|
|
memset( dst, 0, dstimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void imgAllocCopyChannelToAlpha( imgImage *dstimage, imgImage *srcimage, int channelindex, unsigned char r, unsigned char g, unsigned char b )
|
|
{
|
|
int x, y;
|
|
unsigned char *dst, *src, *dstrow, *srcrow;
|
|
|
|
dstimage->format.width = srcimage->format.width;
|
|
dstimage->format.height = srcimage->format.height;
|
|
dstimage->format.type = IMG_FORMAT_TYPE_RGBA32;
|
|
dstimage->format.bytesperpixel = 4;
|
|
dstimage->format.bytesperline = dstimage->format.width * dstimage->format.bytesperpixel;
|
|
dstimage->data = malloc( dstimage->format.height * dstimage->format.bytesperline );
|
|
|
|
src = ADDRESS( srcimage->data, channelindex );
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < dstimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = dst;
|
|
for( x = 0 ; x < dstimage->format.width ; x++ )
|
|
{
|
|
dstrow[0] = r;
|
|
dstrow[1] = g;
|
|
dstrow[2] = b;
|
|
dstrow[3] = *srcrow;
|
|
srcrow = ADDRESS( srcrow, srcimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, dstimage->format.bytesperpixel );
|
|
}
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void imgAllocAdjustBrightnessContrast( imgImage *dstimage, imgImage *srcimage, float brightness, float contrast )
|
|
{
|
|
int x, y;
|
|
float r, g, b;
|
|
unsigned char *dst, *src, *dstrow, *srcrow;
|
|
|
|
dstimage->format = srcimage->format;
|
|
dstimage->data = malloc( srcimage->format.height * srcimage->format.bytesperline );
|
|
|
|
brightness += 0.5f;
|
|
|
|
if( dstimage->format.bytesperpixel >= 3 )
|
|
{
|
|
src = srcimage->data;
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < dstimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = dst;
|
|
for( x = 0 ; x < dstimage->format.width ; x++ )
|
|
{
|
|
r = (1.0f/255.0f) * (float)srcrow[0];
|
|
g = (1.0f/255.0f) * (float)srcrow[1];
|
|
b = (1.0f/255.0f) * (float)srcrow[2];
|
|
r = ( ( r - 0.5f ) * contrast ) + brightness;
|
|
g = ( ( g - 0.5f ) * contrast ) + brightness;
|
|
b = ( ( b - 0.5f ) * contrast ) + brightness;
|
|
dstrow[0] = (unsigned char)fmaxf( 0.0f, fminf( 255.0f, roundf( r * 255.0f ) ) );
|
|
dstrow[1] = (unsigned char)fmaxf( 0.0f, fminf( 255.0f, roundf( g * 255.0f ) ) );
|
|
dstrow[2] = (unsigned char)fmaxf( 0.0f, fminf( 255.0f, roundf( b * 255.0f ) ) );
|
|
if( dstimage->format.bytesperpixel >= 4 )
|
|
dstrow[3] = srcrow[3];
|
|
srcrow = ADDRESS( srcrow, srcimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, dstimage->format.bytesperpixel );
|
|
}
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
}
|
|
else if( dstimage->format.bytesperpixel == 1 )
|
|
{
|
|
src = srcimage->data;
|
|
dst = dstimage->data;
|
|
for( y = 0 ; y < dstimage->format.height ; y++ )
|
|
{
|
|
srcrow = src;
|
|
dstrow = dst;
|
|
for( x = 0 ; x < dstimage->format.width ; x++ )
|
|
{
|
|
r = (1.0f/255.0f) * (float)srcrow[0];
|
|
r = ( ( r - 0.5f ) * contrast ) + brightness;
|
|
dstrow[0] = (unsigned char)fmaxf( 0.0f, fminf( 255.0f, roundf( r * 255.0f ) ) );
|
|
srcrow = ADDRESS( srcrow, srcimage->format.bytesperpixel );
|
|
dstrow = ADDRESS( dstrow, dstimage->format.bytesperpixel );
|
|
}
|
|
src = ADDRESS( src, srcimage->format.bytesperline );
|
|
dst = ADDRESS( dst, dstimage->format.bytesperline );
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void imgFree( imgImage *image )
|
|
{
|
|
free( image->data );
|
|
image->data = 0;
|
|
return;
|
|
}
|
|
|
|
|
|
////
|
|
|
|
|