<commit_before>/*
* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Image implementation
*
*/


/*!
 * \internal
 * \file
 * \brief Image implementation
 *
 */

#ifndef M3G_CORE_INCLUDE
#   error included by m3g_core.c; do not compile separately.
#endif

#include "m3g_image.h"
#include "m3g_texture.h"

/* Declare prototypes for some of the helper functions called from the
 * platform-dependent code included below */

static M3Gint  m3gBytesPerPixel(M3GPixelFormat format);
static M3Gint  m3gGetNumMipmapLevels(M3Gint w, M3Gint h);
static void m3gDownsample(M3GPixelFormat format, const M3Gubyte *srcPixels, M3Gint *pw, M3Gint *ph, M3Gubyte *dstPixels);
static void m3gFreeImageData(Image *img);

/* Include platform-dependent functionality */
#include "m3g_image.inl"

/* Size of the buffer used in pixel format conversions; this should be
 * an even number */
#define SPAN_BUFFER_SIZE 32

M3G_CT_ASSERT((SPAN_BUFFER_SIZE & 1) == 0);

/*----------------------------------------------------------------------
 * Private functions
 *--------------------------------------------------------------------*/

/*!
 * \internal
 * \brief Destroys this Image object.
 *
 * \param obj Image object
 */
static void m3gDestroyImage(Object *obj)
{
    Image *image = (Image*)obj;
    Interface *m3g = M3G_INTERFACE(image);
    M3G_VALIDATE_OBJECT(image);

    if (!image->copyOf) {
        m3gFreeObject(m3g, image->data);
        m3gFreeObject(m3g, image->mipData);
    }
    M3G_ASSIGN_REF(image->copyOf, NULL);
    
    if (image->powerOfTwo != image) {
        M3G_ASSIGN_REF(image->powerOfTwo, NULL);
    }

#   if !defined(M3G_NGL_TEXTURE_API)
    if (image->texObject) {
        m3gDeleteGLTextures(m3g, 1, &image->texObject);
    }
    if (image->large != NULL) {
        m3gDestroyLargeImage(image);
    }
#   endif

    m3gDestroyObject(obj);
}

/*--------------------------------------------------------------------*/

#define RED(argb)   (((argb) >> 16) & 0xFFu)
#define GREEN(argb) (((argb) >>  8) & 0xFFu)
#define BLUE(argb)  ( (argb)        & 0xFFu)
#define ALPHA(argb) (((argb) >> 24) & 0xFFu)

#define RGBSUM(argb) (0x4CB2u * RED(argb) +     \
                      0x9691u * GREEN(argb) +   \
                      0x1D3Eu * BLUE(argb))

/*!
 * \internal \brief ARGB -> A
 */
static void convertARGBToA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        *dst++ = (M3Gubyte) ALPHA(*src++);
    }
}

/*!
 * \internal \brief ARGB -> L
 */
static void convertARGBToL8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(sum >> 16);
    }
}

/*!
 * \internal \brief ARGB -> LA */
static void convertARGBToLA4(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(((sum >> 16) & 0xF0) | ((argb >> 28) & 0x0F));
    }
}

/*!
 * \internal \brief ARGB -> LA8
 */
static void convertARGBToLA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(sum >> 16);       /* L */
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

/*!
 * \internal \brief ARGB -> RGB
 */
static void convertARGBToRGB8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) BLUE(argb);
    }
}

/*!
 * \internal \brief ARGB -> RGB565
 */
static void convertARGBToRGB565(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *(M3Gushort*)dst = (M3Gushort)(((argb >> 8) & 0xF800u)|
                                       ((argb >> 5) & 0x07E0u)|
                                       ((argb >> 3) & 0x001Fu));
        dst += 2;
    }
}

/*!
 * \internal \brief ARGB -> RGBA
 */
static void convertARGBToRGBA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) BLUE(argb);
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

/*!
 * \internal \brief ARGB -> BGRA
 */
static void convertARGBToBGRA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) BLUE(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

#undef RED
#undef GREEN
#undef BLUE
#undef ALPHA

/*!
 * \internal
 * \brief Converts a span of ARGB pixels to another format
 *
 * \param src   source pixels
 * \param count pixel count
 * \param dstFormat destination format
 * \param dst destination pixels
 */
static void convertFromARGB(const M3Guint *src,
                            M3Gsizei count,
                            M3GPixelFormat dstFormat,
                            M3Gubyte *dst)
{
    switch (dstFormat) {
    case M3G_L8:
        convertARGBToL8(src, count, dst);
        break;
    case M3G_A8:
        convertARGBToA8(src, count, dst);
        break;
    case M3G_LA4:
        convertARGBToLA4(src, count, dst);
        break;
    case M3G_LA8:
        convertARGBToLA8(src, count, dst);
        break;
    case M3G_RGB8:
        convertARGBToRGB8(src, count, dst);
        break;
    case M3G_RGB565:
        convertARGBToRGB565(src, count, dst);
        break;
    case M3G_RGBA8:
    case M3G_RGB8_32:
        convertARGBToRGBA8(src, count, dst);
        break;
    case M3G_BGRA8:
    case M3G_BGR8_32:
        convertARGBToBGRA8(src, count, dst);
        break;
    default:
        M3G_ASSERT(M3G_FALSE);  /* conversion not supported */
    }
}

/*--------------------------------------------------------------------*/

/*!
 * \internal \brief A8 -> ARGB
 */
static void convertA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_RGB_MASK;
        argb |= ((M3Guint) *src++) << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief L8 -> ARGB
 */
static void convertL8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        argb |= (argb << 8) | (argb << 16);
        argb |= M3G_ALPHA_MASK;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief LA8 -> ARGB
 */
static void convertLA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        argb |= (argb << 8) | (argb << 16);
        argb |= ((M3Guint) *src++) << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief RGB8 -> ARGB
 */
static void convertRGB8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_ALPHA_MASK;
        argb |= ((M3Guint)(*src++)) << 16;
        argb |= ((M3Guint)(*src++)) <<  8;
        argb |=  (M3Guint)(*src++);
        *dst++ = argb;
    }
}

/*!
 * \internal \brief RGB565 -> ARGB
 */
static void convertRGB565ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_ALPHA_MASK;
        const M3Guint rgb565 = *(const M3Gushort*)src;
        argb |= ((rgb565 & 0xF800u) << 8)|((rgb565 & 0xE000u) << 3);
        argb |= ((rgb565 & 0x07E0u) << 5)|((rgb565 & 0x0600u) >> 1);
        argb |= ((rgb565 & 0x001Fu) << 3)|((rgb565 & 0x001Cu) >> 2);
        *dst++ = argb;
        src += 2;
    }
}

/*!
 * \internal \brief RGBA8 -> ARGB
 */
static void convertRGBA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb;
        argb  = ((M3Guint)(*src++)) << 16;
        argb |= ((M3Guint)(*src++)) <<  8;
        argb |=  (M3Guint)(*src++);
        argb |= ((M3Guint)(*src++)) << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief BGRA8 -> ARGB
 */
static void convertBGRA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb;
        argb  =  (M3Guint)(*src++);
        argb |= ((M3Guint)(*src++)) <<  8;<commit_msg>Use workaround for alpha drawing in m3g<commit_after>/*
* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Image implementation
*
*/


/*!
 * \internal
 * \file
 * \brief Image implementation
 *
 */

#ifndef M3G_CORE_INCLUDE
#   error included by m3g_core.c; do not compile separately.
#endif

#include "m3g_image.h"
#include "m3g_texture.h"

/* Declare prototypes for some of the helper functions called from the
 * platform-dependent code included below */

static M3Gint  m3gBytesPerPixel(M3GPixelFormat format);
static M3Gint  m3gGetNumMipmapLevels(M3Gint w, M3Gint h);
static void m3gDownsample(M3GPixelFormat format, const M3Gubyte *srcPixels, M3Gint *pw, M3Gint *ph, M3Gubyte *dstPixels);
static void m3gFreeImageData(Image *img);

/* Include platform-dependent functionality */
#include "m3g_image.inl"

/* Size of the buffer used in pixel format conversions; this should be
 * an even number */
#define SPAN_BUFFER_SIZE 32

M3G_CT_ASSERT((SPAN_BUFFER_SIZE & 1) == 0);

/*----------------------------------------------------------------------
 * Private functions
 *--------------------------------------------------------------------*/

/*!
 * \internal
 * \brief Destroys this Image object.
 *
 * \param obj Image object
 */
static void m3gDestroyImage(Object *obj)
{
    Image *image = (Image*)obj;
    Interface *m3g = M3G_INTERFACE(image);
    M3G_VALIDATE_OBJECT(image);

    if (!image->copyOf) {
        m3gFreeObject(m3g, image->data);
        m3gFreeObject(m3g, image->mipData);
    }
    M3G_ASSIGN_REF(image->copyOf, NULL);
    
    if (image->powerOfTwo != image) {
        M3G_ASSIGN_REF(image->powerOfTwo, NULL);
    }

#   if !defined(M3G_NGL_TEXTURE_API)
    if (image->texObject) {
        m3gDeleteGLTextures(m3g, 1, &image->texObject);
    }
    if (image->large != NULL) {
        m3gDestroyLargeImage(image);
    }
#   endif

    m3gDestroyObject(obj);
}

/*--------------------------------------------------------------------*/

#define RED(argb)   (((argb) >> 16) & 0xFFu)
#define GREEN(argb) (((argb) >>  8) & 0xFFu)
#define BLUE(argb)  ( (argb)        & 0xFFu)
#define ALPHA(argb) (((argb) >> 24) & 0xFFu)

#define RGBSUM(argb) (0x4CB2u * RED(argb) +     \
                      0x9691u * GREEN(argb) +   \
                      0x1D3Eu * BLUE(argb))

/*!
 * \internal \brief ARGB -> A
 */
static void convertARGBToA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        *dst++ = (M3Gubyte) ALPHA(*src++);
    }
}

/*!
 * \internal \brief ARGB -> L
 */
static void convertARGBToL8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(sum >> 16);
    }
}

/*!
 * \internal \brief ARGB -> LA */
static void convertARGBToLA4(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(((sum >> 16) & 0xF0) | ((argb >> 28) & 0x0F));
    }
}

/*!
 * \internal \brief ARGB -> LA8
 */
static void convertARGBToLA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        M3Guint sum = RGBSUM(argb);
        *dst++ = (M3Gubyte)(sum >> 16);       /* L */
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

/*!
 * \internal \brief ARGB -> RGB
 */
static void convertARGBToRGB8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) BLUE(argb);
    }
}

/*!
 * \internal \brief ARGB -> RGB565
 */
static void convertARGBToRGB565(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *(M3Gushort*)dst = (M3Gushort)(((argb >> 8) & 0xF800u)|
                                       ((argb >> 5) & 0x07E0u)|
                                       ((argb >> 3) & 0x001Fu));
        dst += 2;
    }
}

/*!
 * \internal \brief ARGB -> RGBA
 */
static void convertARGBToRGBA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) BLUE(argb);
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

/*!
 * \internal \brief ARGB -> BGRA
 */
static void convertARGBToBGRA8(const M3Guint *src, M3Gsizei count, M3Gubyte *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        *dst++ = (M3Gubyte) BLUE(argb);
        *dst++ = (M3Gubyte) GREEN(argb);
        *dst++ = (M3Gubyte) RED(argb);
        *dst++ = (M3Gubyte) ALPHA(argb);
    }
}

#undef RED
#undef GREEN
#undef BLUE
#undef ALPHA

/*!
 * \internal
 * \brief Converts a span of ARGB pixels to another format
 *
 * \param src   source pixels
 * \param count pixel count
 * \param dstFormat destination format
 * \param dst destination pixels
 */
static void convertFromARGB(const M3Guint *src,
                            M3Gsizei count,
                            M3GPixelFormat dstFormat,
                            M3Gubyte *dst)
{
    switch (dstFormat) {
    case M3G_L8:
        convertARGBToL8(src, count, dst);
        break;
    case M3G_A8:
        convertARGBToA8(src, count, dst);
        break;
    case M3G_LA4:
        convertARGBToLA4(src, count, dst);
        break;
    case M3G_LA8:
        convertARGBToLA8(src, count, dst);
        break;
    case M3G_RGB8:
        convertARGBToRGB8(src, count, dst);
        break;
    case M3G_RGB565:
        convertARGBToRGB565(src, count, dst);
        break;
    case M3G_RGBA8:
    case M3G_RGB8_32:
        convertARGBToRGBA8(src, count, dst);
        break;
    case M3G_BGRA8:
    case M3G_BGR8_32:
        convertARGBToBGRA8(src, count, dst);
        break;
    default:
        M3G_ASSERT(M3G_FALSE);  /* conversion not supported */
    }
}

/*--------------------------------------------------------------------*/

/*!
 * \internal \brief A8 -> ARGB
 */
static void convertA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_RGB_MASK;
        argb |= ((M3Guint) *src++) << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief L8 -> ARGB
 */
static void convertL8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        argb |= (argb << 8) | (argb << 16);
        argb |= M3G_ALPHA_MASK;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief LA8 -> ARGB
 */
static void convertLA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = *src++;
        argb |= (argb << 8) | (argb << 16);
        argb |= ((M3Guint) *src++) << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief RGB8 -> ARGB
 */
static void convertRGB8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_ALPHA_MASK;
        argb |= ((M3Guint)(*src++)) << 16;
        argb |= ((M3Guint)(*src++)) <<  8;
        argb |=  (M3Guint)(*src++);
        *dst++ = argb;
    }
}

/*!
 * \internal \brief RGB565 -> ARGB
 */
static void convertRGB565ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb = M3G_ALPHA_MASK;
        const M3Guint rgb565 = *(const M3Gushort*)src;
        argb |= ((rgb565 & 0xF800u) << 8)|((rgb565 & 0xE000u) << 3);
        argb |= ((rgb565 & 0x07E0u) << 5)|((rgb565 & 0x0600u) >> 1);
        argb |= ((rgb565 & 0x001Fu) << 3)|((rgb565 & 0x001Cu) >> 2);
        *dst++ = argb;
        src += 2;
    }
}

/*!
 * \internal \brief RGBA8 -> ARGB
 */
static void convertRGBA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb;
        argb  = ((M3Guint)(*src++)) << 16;
        argb |= ((M3Guint)(*src++)) <<  8;
        argb |=  (M3Guint)(*src++);
        // Workaround for Android
        // TODO fix it
        M3Guint alpha = (M3Guint)(*src++);
        if (argb != 0 && alpha == 0) {
            alpha = 0xFF;
        }
        argb |= alpha << 24;
        *dst++ = argb;
    }
}

/*!
 * \internal \brief BGRA8 -> ARGB
 */
static void convertBGRA8ToARGB(const M3Gubyte *src, M3Gsizei count, M3Guint *dst)
{
    while (count--) {
        M3Guint argb;
        argb  =  (M3Guint)(*src++);
        argb |= ((M3Guint)(*src++)) <<  8;
{'fraction_non_alphanumeric': 0.17936607295282536, 'fraction_numerical': 0.03886644283844534, 'mean_word_length': 2.1883164005805513, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '103756', 'n_tokens_mistral': 6989, 'n_tokens_neox': 6683, 'n_words': 1503}