LCOV - code coverage report
Current view: top level - Core/Materials - OOPixMapChannelOperations.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 12 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOPixMapChannelOperations.m
       4             : 
       5             : 
       6             : Copyright (C) 2010-2013 Jens Ayton
       7             : 
       8             : Permission is hereby granted, free of charge, to any person obtaining a copy
       9             : of this software and associated documentation files (the "Software"), to deal
      10             : in the Software without restriction, including without limitation the rights
      11             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      12             : copies of the Software, and to permit persons to whom the Software is
      13             : furnished to do so, subject to the following conditions:
      14             : 
      15             : The above copyright notice and this permission notice shall be included in all
      16             : copies or substantial portions of the Software.
      17             : 
      18             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      19             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      20             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      21             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      22             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      24             : SOFTWARE.
      25             : 
      26             : */
      27             : 
      28             : #include "OOPixMapChannelOperations.h"
      29             : #import "OOCPUInfo.h"
      30             : 
      31             : 
      32             : static void ExtractChannel_4(OOPixMap *ioPixMap, uint8_t channelIndex);
      33             : static void ToRGBA_1(OOPixMap srcPx, OOPixMap dstPx);
      34             : static void ToRGBA_2(OOPixMap srcPx, OOPixMap dstPx);
      35             : static void ModulateUniform_4(OOPixMap pixMap, uint16_t f0, uint16_t f1, uint16_t f2, uint16_t f3);
      36             : static void ModulatePixMap_4(OOPixMap mainPx, OOPixMap otherPx);
      37             : static void AddPixMap_4(OOPixMap mainPx, OOPixMap otherPx);
      38             : 
      39             : 
      40           0 : BOOL OOExtractPixMapChannel(OOPixMap *ioPixMap, uint8_t channelIndex, BOOL compactWhenDone)
      41             : {
      42             :         if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap) || ioPixMap->format != kOOPixMapRGBA || channelIndex > 3))
      43             :         {
      44             :                 return NO;
      45             :         }
      46             :         
      47             :         ExtractChannel_4(ioPixMap, channelIndex);
      48             :         
      49             :         ioPixMap->format = kOOPixMapGrayscale;
      50             :         ioPixMap->rowBytes = ioPixMap->width;
      51             :         
      52             :         if (compactWhenDone)
      53             :         {
      54             :                 OOCompactPixMap(ioPixMap);
      55             :         }
      56             :         
      57             :         return YES;
      58             : }
      59             : 
      60             : 
      61           0 : static void ExtractChannel_4(OOPixMap *ioPixMap, uint8_t channelIndex)
      62             : {
      63             :         NSCParameterAssert(ioPixMap != NULL);
      64             :         
      65             :         uint32_t                        *src;
      66             :         uint8_t                         *dst;
      67             :         uint_fast8_t            shift;
      68             :         uint_fast32_t           xCount, y;
      69             :         
      70             :         dst = ioPixMap->pixels;
      71             :         shift = 8 * channelIndex;
      72             :         
      73             :         for (y = 0; y < ioPixMap->height; y++)
      74             :         {
      75             :                 src = (uint32_t *)((char *)ioPixMap->pixels + y * ioPixMap->rowBytes);
      76             :                 xCount = ioPixMap->width;
      77             :                 
      78             :                 do
      79             :                 {
      80             :                         *dst++ = (*src++ >> shift) & 0xFF;
      81             :                 }
      82             :                 while (--xCount);
      83             :         }
      84             : }
      85             : 
      86             : 
      87           0 : BOOL OOPixMapToRGBA(OOPixMap *ioPixMap)
      88             : {
      89             :         if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap)))  return NO;
      90             :         if (ioPixMap->format == kOOPixMapRGBA)  return YES;
      91             :         
      92             :         OOPixMap temp = OOAllocatePixMap(ioPixMap->width, ioPixMap->height, 4, 0, 0);
      93             :         if (EXPECT_NOT(OOIsNullPixMap(temp)))  return NO;
      94             :         
      95             :         BOOL OK = NO;
      96             :         switch (ioPixMap->format)
      97             :         {
      98             :                 case kOOPixMapGrayscale:
      99             :                         ToRGBA_1(*ioPixMap, temp);
     100             :                         OK = YES;
     101             :                         break;
     102             :                         
     103             :                 case kOOPixMapGrayscaleAlpha:
     104             :                         ToRGBA_2(*ioPixMap, temp);
     105             :                         OK = YES;
     106             :                         break;
     107             :                         
     108             :                 case kOOPixMapRGBA:
     109             :                 case kOOPixMapInvalidFormat:
     110             :                         OK = NO;
     111             :                         break;
     112             :                         // No default, because -Wswitch-enum is our friend.
     113             :         }
     114             :         
     115             :         if (OK)
     116             :         {
     117             :                 free(ioPixMap->pixels);
     118             :                 *ioPixMap = temp;
     119             :         }
     120             :         else
     121             :         {
     122             :                 free(temp.pixels);
     123             :         }
     124             : 
     125             :         return OK;
     126             : }
     127             : 
     128             : 
     129           0 : static void ToRGBA_1(OOPixMap srcPx, OOPixMap dstPx)
     130             : {
     131             :         NSCParameterAssert(OOPixMapBytesPerPixel(srcPx) == 1 && dstPx.format == kOOPixMapRGBA && srcPx.width == dstPx.width && srcPx.height == dstPx.height);
     132             :         
     133             :         uint8_t                         *src;
     134             :         uint32_t                        *dst;
     135             :         uint_fast32_t           xCount, y;
     136             :         
     137             :         dst = dstPx.pixels;
     138             :         
     139             :         for (y = 0; y < srcPx.height; y++)
     140             :         {
     141             :                 src = (uint8_t *)((char *)srcPx.pixels + y * srcPx.rowBytes);
     142             :                 xCount = srcPx.width;
     143             :                 
     144             :                 do
     145             :                 {
     146             :                         *dst++ = (*src++ * 0x00010101) | 0xFF000000;
     147             :                 }
     148             :                 while (--xCount);
     149             :         }
     150             : }
     151             : 
     152             : 
     153           0 : static void ToRGBA_2(OOPixMap srcPx, OOPixMap dstPx)
     154             : {
     155             :         NSCParameterAssert(OOPixMapBytesPerPixel(srcPx) == 2 && dstPx.format == kOOPixMapRGBA && srcPx.width == dstPx.width && srcPx.height == dstPx.height);
     156             :         
     157             :         uint16_t                        *src;
     158             :         uint_fast32_t           px;
     159             :         uint32_t                        *dst;
     160             :         uint_fast32_t           xCount, y;
     161             :         
     162             :         dst = dstPx.pixels;
     163             :         
     164             :         for (y = 0; y < srcPx.height; y++)
     165             :         {
     166             :                 src = (uint16_t *)((char *)srcPx.pixels + y * srcPx.rowBytes);
     167             :                 xCount = srcPx.width;
     168             :                 
     169             :                 do
     170             :                 {
     171             :                         px = *src++;
     172             : #if OOLITE_BIG_ENDIAN
     173             :                         *dst++ = (((px & 0xFF00) >> 8) * 0x00010101) | ((px & 0x00FF) << 24);
     174             : #elif OOLITE_LITTLE_ENDIAN
     175             :                         *dst++ = ((px & 0x00FF) * 0x00010101) | ((px & 0xFF00) << 16);
     176             : #else
     177             : #error Unknown byte order.
     178             : #endif
     179             :                 }
     180             :                 while (--xCount);
     181             :         }
     182             : }
     183             : 
     184             : 
     185           0 : BOOL OOPixMapModulateUniform(OOPixMap *ioPixMap, float f0, float f1, float f2, float f3)
     186             : {
     187             :         if (EXPECT_NOT(ioPixMap == NULL || !OOIsValidPixMap(*ioPixMap)))  return NO;
     188             :         if (EXPECT_NOT(!OOPixMapToRGBA(ioPixMap)))  return NO;
     189             :         
     190             :         ModulateUniform_4(*ioPixMap, f0 * 256.0f, f1 * 256.0f, f2 * 256.0f, f3 * 256.0f);
     191             :         
     192             :         return YES;
     193             : }
     194             : 
     195             : 
     196           0 : static void ModulateUniform_4(OOPixMap pixMap, uint16_t f3, uint16_t f2, uint16_t f1, uint16_t f0)
     197             : {
     198             :         NSCParameterAssert(OOPixMapBytesPerPixel(pixMap) == 4);
     199             :         
     200             :         uint32_t                        *curr;
     201             :         uint_fast32_t           px;
     202             :         uint_fast32_t           p0, p1, p2, p3;
     203             :         uint_fast32_t           xCount, y;
     204             :         
     205             :         for (y = 0; y < pixMap.height; y++)
     206             :         {
     207             :                 curr = (uint32_t *)((char *)pixMap.pixels + y * pixMap.rowBytes);
     208             :                 xCount = pixMap.width;
     209             :                 
     210             :                 do
     211             :                 {
     212             :                         px = *curr;
     213             :                         
     214             :                         /*      Principle of operation:
     215             :                                 Each pixel component is in the range 0..0xFF.
     216             :                                 Each constant factor component is in the range 0..0x100.
     217             :                                 Multiplying them therefore gives us a result in the range
     218             :                                 0x0000..0xFF00. The bottom byte is discarded by shifting
     219             :                                 and masking.
     220             :                         */
     221             :                         
     222             :                         p0 = px & 0xFF000000;
     223             :                         p0 = ((p0 >> 8) * f0) & 0xFF000000;
     224             :                         
     225             :                         p1 = px & 0x00FF0000;
     226             :                         p1 = ((p1 * f1) >> 8) & 0x00FF0000;
     227             :                         
     228             :                         p2 = px & 0x0000FF00;
     229             :                         p2 = ((p2 * f2) >> 8) & 0x0000FF00;
     230             :                         
     231             :                         p3 = px & 0x000000FF;
     232             :                         p3 = ((p3 * f3) >> 8) & 0x000000FF;
     233             :                         
     234             :                         px = p0 | p1 | p2 | p3;
     235             :                         *curr++ = px;
     236             :                 }
     237             :                 while (--xCount);
     238             :         }
     239             : }
     240             : 
     241             : 
     242           0 : BOOL OOPixMapModulatePixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
     243             : {
     244             :         if (EXPECT_NOT(ioDstPixMap == NULL || !OOIsValidPixMap(*ioDstPixMap)))  return NO;
     245             :         if (EXPECT_NOT(!OOIsValidPixMap(otherPixMap) || otherPixMap.format != kOOPixMapRGBA))  return NO;
     246             :         if (EXPECT_NOT(!OOPixMapToRGBA(ioDstPixMap)))  return NO;
     247             :         if (EXPECT_NOT(ioDstPixMap->width != otherPixMap.width || ioDstPixMap->height != otherPixMap.height))  return NO;
     248             :         
     249             :         ModulatePixMap_4(*ioDstPixMap, otherPixMap);
     250             :         
     251             :         return YES;
     252             : }
     253             : 
     254             : 
     255           0 : static void ModulatePixMap_4(OOPixMap mainPx, OOPixMap otherPx)
     256             : {
     257             :         uint32_t                        *dst, *other;
     258             :         uint_fast32_t           px;
     259             :         uint_fast16_t           m0, m1, m2, m3;
     260             :         uint_fast16_t           o0, o1, o2, o3;
     261             :         uint_fast32_t           xCount, y;
     262             :         
     263             :         for (y = 0; y < mainPx.height; y++)
     264             :         {
     265             :                 dst = (uint32_t *)((char *)mainPx.pixels + y * mainPx.rowBytes);
     266             :                 other = (uint32_t *)((char *)otherPx.pixels + y * otherPx.rowBytes);
     267             :                 xCount = mainPx.width;
     268             :                 
     269             :                 do
     270             :                 {
     271             :                         px = *dst;
     272             :                         m0 = (px >> 24) & 0xFF;
     273             :                         m1 = (px >> 16) & 0xFF;
     274             :                         m2 = (px >> 8) & 0xFF;
     275             :                         m3 = px & 0xFF;
     276             :                         
     277             :                         px = *other;
     278             :                         o0 = (px >> 24) & 0xFF;
     279             :                         o1 = (px >> 16) & 0xFF;
     280             :                         o2 = (px >> 8) & 0xFF;
     281             :                         o3 = px & 0xFF;
     282             :                         
     283             :                         /*      Unlike in ModulateUniform(), neither side here goes to 256, so
     284             :                                 we have to divide by 255 rather than shifting. However, the
     285             :                                 compiler should be able to optimize this to a multiplication
     286             :                                 by a magic number.
     287             :                         */
     288             :                         m0 = (m0 * o0) / 255;
     289             :                         m1 = (m1 * o1) / 255;
     290             :                         m2 = (m2 * o2) / 255;
     291             :                         m3 = (m3 * o3) / 255;
     292             :                         
     293             :                         *dst++ = ((uint_fast32_t)m0 << 24) | ((uint_fast32_t)m1 << 16) | (m2 << 8) | m3;
     294             :                         other++;
     295             :                 }
     296             :                 while (--xCount);
     297             :         }
     298             : }
     299             : 
     300             : 
     301           0 : BOOL OOPixMapAddPixMap(OOPixMap *ioDstPixMap, OOPixMap otherPixMap)
     302             : {
     303             :         if (EXPECT_NOT(ioDstPixMap == NULL || !OOIsValidPixMap(*ioDstPixMap)))  return NO;
     304             :         if (EXPECT_NOT(!OOIsValidPixMap(otherPixMap) || otherPixMap.format != kOOPixMapRGBA))  return NO;
     305             :         if (EXPECT_NOT(!OOPixMapToRGBA(ioDstPixMap)))  return NO;
     306             :         if (EXPECT_NOT(ioDstPixMap->width != otherPixMap.width || ioDstPixMap->height != otherPixMap.height))  return NO;
     307             :         
     308             :         AddPixMap_4(*ioDstPixMap, otherPixMap);
     309             :         
     310             :         return YES;
     311             : }
     312             : 
     313             : 
     314           0 : static void AddPixMap_4(OOPixMap mainPx, OOPixMap otherPx)
     315             : {
     316             :         uint32_t                        *dst, *other;
     317             :         uint_fast32_t           px;
     318             :         uint_fast32_t           m02, m13;
     319             :         uint_fast32_t           o02, o13;
     320             :         uint_fast32_t           xCount, y;
     321             :         
     322             :         for (y = 0; y < mainPx.height; y++)
     323             :         {
     324             :                 dst = (uint32_t *)((char *)mainPx.pixels + y * mainPx.rowBytes);
     325             :                 other = (uint32_t *)((char *)otherPx.pixels + y * otherPx.rowBytes);
     326             :                 xCount = mainPx.width;
     327             :                 
     328             :                 do
     329             :                 {
     330             :                         px = *dst;
     331             :                         m02 = (px & 0xFF00FF00) >> 8;
     332             :                         m13 = px & 0x00FF00FF;
     333             :                         
     334             :                         px = *other;
     335             :                         o02 = (px & 0xFF00FF00) >> 8;
     336             :                         o13 = px & 0x00FF00FF;
     337             :                         
     338             :                         /*      Saturated adds, two components at a time.
     339             :                                 By masking out the overflow bits of each component,
     340             :                                 multiplying them by 0xFF and shifting right one byte, we get a
     341             :                                 mask that's oxFF for components that overflowed and 0x00 for
     342             :                                 components that did not, without any conditionals.
     343             :                         */
     344             :                         m02 += o02;
     345             :                         m02 |= ((m02 & 0x01000100) * 0xFF) >> 8;
     346             :                         m13 += o13;
     347             :                         m13 |= ((m13 & 0x01000100) * 0xFF) >> 8;
     348             :                         
     349             :                         *dst++ = ((m02 << 8) & 0xFF00FF00) | (m13 & 0x00FF00FF);
     350             :                         other++;
     351             :                 }
     352             :                 while (--xCount);
     353             :         }
     354             : }
     355             : 

Generated by: LCOV version 1.14