From 8e65f0188fa601ef97560dfe2e47cea0e88fe683 Mon Sep 17 00:00:00 2001 From: Marcus Huderle Date: Sun, 10 Nov 2019 16:29:52 -0600 Subject: Rename contest_painting_effects to image_processing_effects --- src/contest_painting.c | 40 +- src/contest_painting_effects.c | 1384 ---------------------------------------- src/image_processing_effects.c | 1384 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1404 insertions(+), 1404 deletions(-) delete mode 100644 src/contest_painting_effects.c create mode 100644 src/image_processing_effects.c (limited to 'src') diff --git a/src/contest_painting.c b/src/contest_painting.c index 40931d7d1..d5eb39565 100644 --- a/src/contest_painting.c +++ b/src/contest_painting.c @@ -5,10 +5,10 @@ #include "bg.h" #include "contest.h" #include "contest_painting.h" -#include "contest_painting_effects.h" #include "data.h" #include "decompress.h" #include "gpu_regs.h" +#include "image_processing_effects.h" #include "international_string_util.h" #include "main.h" #include "lilycove_lady.h" @@ -23,7 +23,7 @@ // IWRAM common u16 (*gContestMonPixels)[][32]; -struct ContestPaintingContext gContestPaintingContext; +struct ImageProcessingContext gImageProcessingContext; struct ContestWinner *gContestPaintingWinner; u16 *gContestPaintingMonPalette; @@ -657,38 +657,38 @@ static void AllocPaintingResources(void) static void DoContestPaintingImageProcessing(u8 imageEffect) { - gContestPaintingContext.canvasPixels = gContestMonPixels; - gContestPaintingContext.canvasPalette = gContestPaintingMonPalette; - gContestPaintingContext.paletteStart = 0; - gContestPaintingContext.personality = gContestPaintingWinner->personality % 256; - gContestPaintingContext.columnStart = 0; - gContestPaintingContext.rowStart = 0; - gContestPaintingContext.columnEnd = 64; - gContestPaintingContext.rowEnd = 64; - gContestPaintingContext.canvasWidth = 64; - gContestPaintingContext.canvasHeight = 64; + gImageProcessingContext.canvasPixels = gContestMonPixels; + gImageProcessingContext.canvasPalette = gContestPaintingMonPalette; + gImageProcessingContext.paletteStart = 0; + gImageProcessingContext.personality = gContestPaintingWinner->personality % 256; + gImageProcessingContext.columnStart = 0; + gImageProcessingContext.rowStart = 0; + gImageProcessingContext.columnEnd = 64; + gImageProcessingContext.rowEnd = 64; + gImageProcessingContext.canvasWidth = 64; + gImageProcessingContext.canvasHeight = 64; switch (imageEffect) { case IMAGE_EFFECT_CHARCOAL: case IMAGE_EFFECT_GRAYSCALE_LIGHT: - gContestPaintingContext.quantizeEffect = QUANTIZE_EFFECT_GRAYSCALE; + gImageProcessingContext.quantizeEffect = QUANTIZE_EFFECT_GRAYSCALE; break; case IMAGE_EFFECT_OUTLINE_COLORED: case IMAGE_EFFECT_SHIMMER: case IMAGE_EFFECT_POINTILLISM: default: - gContestPaintingContext.quantizeEffect = QUANTIZE_EFFECT_STANDARD_LIMITED_COLORS; + gImageProcessingContext.quantizeEffect = QUANTIZE_EFFECT_STANDARD_LIMITED_COLORS; break; } - gContestPaintingContext.var_16 = 2; - gContestPaintingContext.effect = imageEffect; - gContestPaintingContext.dest = OBJ_VRAM0; + gImageProcessingContext.var_16 = 2; + gImageProcessingContext.effect = imageEffect; + gImageProcessingContext.dest = OBJ_VRAM0; - ApplyImageProcessingEffects(&gContestPaintingContext); - ApplyImageProcessingQuantization(&gContestPaintingContext); - ConvertImageProcessingToGBA(&gContestPaintingContext); + ApplyImageProcessingEffects(&gImageProcessingContext); + ApplyImageProcessingQuantization(&gImageProcessingContext); + ConvertImageProcessingToGBA(&gImageProcessingContext); LoadPalette(gContestPaintingMonPalette, 0x100, 0x200); } diff --git a/src/contest_painting_effects.c b/src/contest_painting_effects.c deleted file mode 100644 index f3354c900..000000000 --- a/src/contest_painting_effects.c +++ /dev/null @@ -1,1384 +0,0 @@ -#include "global.h" -#include "contest_painting_effects.h" -#include "contest_painting.h" -#include "constants/rgb.h" - -// IWRAM common -u8 gCanvasColumnStart; -u16 (*gCanvasPixels)[][32]; -u8 gCanvasRowEnd; -u8 gCanvasHeight; -u8 gCanvasColumnEnd; -u8 gCanvasRowStart; -u8 gCanvasMonPersonality; -u8 gCanvasWidth; -u16 *gCanvasPalette; -u16 gCanvasPaletteStart; - -static void ApplyImageEffect_Pointillism(void); -static void ApplyImageEffect_Blur(void); -static void ApplyImageEffect_BlackOutline(void); -static void ApplyImageEffect_Invert(void); -static void ApplyImageEffect_BlackAndWhite(void); -static void ApplyImageEffect_BlurRight(void); -static void ApplyImageEffect_BlurDown(void); -static void ApplyImageEffect_Shimmer(void); -static void ApplyImageEffect_Grayscale(void); -static void ApplyImageEffect_PersonalityColor(u8); -static void ApplyImageEffect_RedChannelGrayscale(u8); -static void ApplyImageEffect_RedChannelGrayscaleHighlight(u8); -static void AddPointillismPoints(u16); -static u16 ConvertColorToGrayscale(u16*); -static u16 QuantizePixel_Blur(u16*, u16*, u16*); -static u16 QuantizePixel_PersonalityColor(u16*, u8); -static u16 QuantizePixel_BlackAndWhite(u16*); -static u16 QuantizePixel_BlackOutline(u16*, u16*); -static u16 QuantizePixel_Invert(u16*); -static u16 QuantizePixel_BlurHard(u16*, u16*, u16*); -static u16 QuantizePixel_MotionBlur(u16*, u16*); -static u16 GetColorFromPersonality(u8); -static void QuantizePalette_Standard(bool8); -static void SetPresetPalette_PrimaryColors(void); -static void QuantizePalette_PrimaryColors(void); -static void SetPresetPalette_Grayscale(void); -static void QuantizePalette_Grayscale(void); -static void SetPresetPalette_GrayscaleSmall(void); -static void QuantizePalette_GrayscaleSmall(void); -static void SetPresetPalette_BlackAndWhite(void); -static void QuantizePalette_BlackAndWhite(void); -static u16 QuantizePixel_Standard(u16*); -static u16 QuantizePixel_GrayscaleSmall(u16*); -static u16 QuantizePixel_Grayscale(u16*); -static u16 QuantizePixel_PrimaryColors(u16*); - -extern const u8 gPointillismPoints[][3]; - -void ApplyImageProcessingEffects(struct ContestPaintingContext *context) -{ - gCanvasPixels = context->canvasPixels; - gCanvasMonPersonality = context->personality; - gCanvasColumnStart = context->columnStart; - gCanvasRowStart = context->rowStart; - gCanvasColumnEnd = context->columnEnd; - gCanvasRowEnd = context->rowEnd; - gCanvasWidth = context->canvasWidth; - gCanvasHeight = context->canvasHeight; - - switch (context->effect) - { - case IMAGE_EFFECT_POINTILLISM: - ApplyImageEffect_Pointillism(); - break; - case IMAGE_EFFECT_BLUR: - ApplyImageEffect_Blur(); - break; - case IMAGE_EFFECT_OUTLINE_COLORED: - ApplyImageEffect_BlackOutline(); - ApplyImageEffect_PersonalityColor(gCanvasMonPersonality); - break; - case IMAGE_EFFECT_INVERT_BLACK_WHITE: - ApplyImageEffect_BlackOutline(); - ApplyImageEffect_Invert(); - ApplyImageEffect_BlackAndWhite(); - case IMAGE_EFFECT_INVERT: - ApplyImageEffect_Invert(); - break; - case IMAGE_EFFECT_THICK_BLACK_WHITE: - ApplyImageEffect_BlackOutline(); - ApplyImageEffect_BlurRight(); - ApplyImageEffect_BlurRight(); - ApplyImageEffect_BlurDown(); - ApplyImageEffect_BlackAndWhite(); - break; - case IMAGE_EFFECT_SHIMMER: - ApplyImageEffect_Shimmer(); - break; - case IMAGE_EFFECT_OUTLINE: - ApplyImageEffect_BlackOutline(); - break; - case IMAGE_EFFECT_BLUR_RIGHT: - ApplyImageEffect_BlurRight(); - break; - case IMAGE_EFFECT_BLUR_DOWN: - ApplyImageEffect_BlurDown(); - break; - case IMAGE_EFFECT_GRAYSCALE_LIGHT: - ApplyImageEffect_Grayscale(); - ApplyImageEffect_RedChannelGrayscale(3); - break; - case IMAGE_EFFECT_CHARCOAL: - ApplyImageEffect_BlackOutline(); - ApplyImageEffect_BlurRight(); - ApplyImageEffect_BlurDown(); - ApplyImageEffect_BlackAndWhite(); - ApplyImageEffect_Blur(); - ApplyImageEffect_Blur(); - ApplyImageEffect_RedChannelGrayscale(2); - ApplyImageEffect_RedChannelGrayscaleHighlight(4); - break; - } -} - -static void ApplyImageEffect_RedChannelGrayscale(u8 delta) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - { - // Gets the grayscale value, based on the pixel's red channel. - // Also adds a delta to skew lighter or darker. - u8 grayValue = (31 & *pixel); - grayValue += delta; - if (grayValue > 31) - grayValue = 31; - - *pixel = RGB2(grayValue, grayValue, grayValue); - } - } - } -} - -static void ApplyImageEffect_RedChannelGrayscaleHighlight(u8 highlight) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - { - u8 grayValue = (31 & *pixel); - if (grayValue > 31 - highlight) - grayValue = 31 - (highlight >> 1); - - *pixel = RGB2(grayValue, grayValue, grayValue); - } - } - } -} - -static void ApplyImageEffect_Pointillism(void) -{ - u32 i; - for (i = 0; i < 3200; i++) - AddPointillismPoints(i); -} - -static void ApplyImageEffect_Grayscale(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = ConvertColorToGrayscale(pixel); - } - } -} - -static void ApplyImageEffect_Blur(void) -{ - u8 i, j; - - for (i = 0; i < gCanvasColumnEnd; i++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart + i]; - u16 prevPixel = *pixel; - - j = 1; - pixel += gCanvasWidth; - while (j < gCanvasRowEnd - 1) - { - if (!(0x8000 & *pixel)) - { - *pixel = QuantizePixel_Blur(&prevPixel, pixel, pixel + gCanvasWidth); - prevPixel = *pixel; - } - - j++; - pixel += gCanvasWidth; - } - } -} - -static void ApplyImageEffect_PersonalityColor(u8 personality) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = QuantizePixel_PersonalityColor(pixel, personality); - } - } -} - -static void ApplyImageEffect_BlackAndWhite(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = QuantizePixel_BlackAndWhite(pixel); - } - } -} - -static void ApplyImageEffect_BlackOutline(void) -{ - u8 i, j; - u16 *pixel; - - // Handle top row of pixels first. - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - pixel = &pixelRow[gCanvasColumnStart]; - *pixel = QuantizePixel_BlackOutline(pixel, pixel + 1); - for (i = 1, pixel++; i < gCanvasColumnEnd - 1; i++, pixel++) - { - *pixel = QuantizePixel_BlackOutline(pixel, pixel + 1); - *pixel = QuantizePixel_BlackOutline(pixel, pixel - 1); - } - - *pixel = QuantizePixel_BlackOutline(pixel, pixel - 1); - } - - // Handle each column from left to right. - for (i = 0; i < gCanvasColumnEnd; i++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; - pixel = &pixelRow[gCanvasColumnStart + i]; - *pixel = QuantizePixel_BlackOutline(pixel, pixel + gCanvasWidth); - for (j = 1, pixel += gCanvasWidth; j < gCanvasRowEnd - 1; j++, pixel += gCanvasWidth) - { - *pixel = QuantizePixel_BlackOutline(pixel, pixel + gCanvasWidth); - *pixel = QuantizePixel_BlackOutline(pixel, pixel - gCanvasWidth); - } - - *pixel = QuantizePixel_BlackOutline(pixel, pixel - gCanvasWidth); - } -} - -static void ApplyImageEffect_Invert(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = QuantizePixel_Invert(pixel); - } - } -} - -static void ApplyImageEffect_Shimmer(void) -{ - u8 i, j; - u16 *pixel; - u16 prevPixel; - - // First, invert all of the colors. - pixel = (*gCanvasPixels)[0]; - for (i = 0; i < 64; i++) - { - for (j = 0; j < 64; j++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = QuantizePixel_Invert(pixel); - } - } - - // Blur the pixels twice. - for (j = 0; j < 64; j++) - { - pixel = &(*gCanvasPixels)[0][j]; - prevPixel = *pixel; - *pixel = 0x8000; - for (i = 1, pixel += 64; i < 63; i++, pixel += 64) - { - if (!(0x8000 & *pixel)) - { - *pixel = QuantizePixel_BlurHard(&prevPixel, pixel, pixel + 64); - prevPixel = *pixel; - } - } - - *pixel = 0x8000; - pixel = &(*gCanvasPixels)[0][j]; - prevPixel = *pixel; - *pixel = 0x8000; - for (i = 1, pixel += 64; i < 63; i++, pixel += 64) - { - if (!(0x8000 & *pixel)) - { - *pixel = QuantizePixel_BlurHard(&prevPixel, pixel, pixel + 64); - prevPixel = *pixel; - } - } - - *pixel = 0x8000; - } - - // Finally, invert colors back to the original color space. - // The above blur causes the outline areas to darken, which makes - // this inversion give the effect of light outlines. - pixel = (*gCanvasPixels)[0]; - for (i = 0; i < 64; i++) - { - for (j = 0; j < 64; j++, pixel++) - { - if (!(0x8000 & *pixel)) - *pixel = QuantizePixel_Invert(pixel); - } - } -} - -static void ApplyImageEffect_BlurRight(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - u16 prevPixel = *pixel; - for (i = 1, pixel++; i < gCanvasColumnEnd - 1; i++, pixel++) - { - if (!(0x8000 & *pixel)) - { - *pixel = QuantizePixel_MotionBlur(&prevPixel, pixel); - prevPixel = *pixel; - } - } - } -} - -static void ApplyImageEffect_BlurDown(void) -{ - u8 i, j; - - for (i = 0; i < gCanvasColumnEnd; i++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart + i]; - u16 prevPixel = *pixel; - for (j = 1, pixel += gCanvasWidth; j < gCanvasRowEnd - 1; j++, pixel += gCanvasWidth) - { - if (!(0x8000 & *pixel)) - { - *pixel = QuantizePixel_MotionBlur(&prevPixel, pixel); - prevPixel = *pixel; - } - } - } -} - -struct PointillismPoint -{ - u8 column; - u8 row; - u16 delta; -}; - -static void AddPointillismPoints(u16 arg0) -{ - u8 i; - bool8 offsetDownLeft; - u8 colorType; - struct PointillismPoint points[6]; - - points[0].column = gPointillismPoints[arg0][0]; - points[0].row = gPointillismPoints[arg0][1]; - points[0].delta = (gPointillismPoints[arg0][2] >> 3) & 7; - - colorType = (gPointillismPoints[arg0][2] >> 1) & 3; - offsetDownLeft = gPointillismPoints[arg0][2] & 1; - for (i = 1; i < points[0].delta; i++) - { - if (!offsetDownLeft) - { - points[i].column = points[0].column - i; - points[i].row = points[0].row + i; - } - else - { - points[i].column = points[0].column + 1; - points[i].row = points[0].row - 1; - } - - if (points[i].column > 63 || points[i].row > 63) - { - points[0].delta = i - 1; - break; - } - - points[i].delta = points[0].delta - i; - } - - for (i = 0; i < points[0].delta; i++) - { - u16 *pixel = &(*gCanvasPixels)[points[i].row * 2][points[i].column]; - - if (!(0x8000 & *pixel)) - { - u16 red = (*pixel) & 0x1F; - u16 green = (*pixel >> 5) & 0x1F; - u16 blue = (*pixel >> 10) & 0x1F; - - switch (colorType) - { - case 0: - case 1: - switch (((gPointillismPoints[arg0][2] >> 3) & 7) % 3) - { - case 0: - if (red >= points[i].delta) - red -= points[i].delta; - else - red = 0; - break; - case 1: - if (green >= points[i].delta) - green -= points[i].delta; - else - green = 0; - break; - case 2: - if (blue >= points[i].delta) - blue -= points[i].delta; - else - blue = 0; - break; - } - break; - case 2: - case 3: - red += points[i].delta; - green += points[i].delta; - blue += points[i].delta; - if (red > 31) - red = 31; - if (green > 31) - green = 31; - if (blue > 31) - blue = 31; - break; - } - - *pixel = RGB2(red, green, blue); - } - } -} - -static u16 ConvertColorToGrayscale(u16 *color) -{ - s32 clr = *color; - s32 r = clr & 0x1F; - s32 g = (clr >> 5) & 0x1F; - s32 b = (clr >> 10) & 0x1F; - s32 gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8; - return RGB2(gray, gray, gray); -} - -// The dark colors are the colored edges of the Cool painting effect. -// Everything else is white. -static u16 QuantizePixel_PersonalityColor(u16 *color, u8 personality) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - - if (red < 17 && green < 17 && blue < 17) - return GetColorFromPersonality(personality); - else - return RGB_WHITE; -} - -// Based on the given value, which comes from the first 8 bits of -// the mon's personality value, return a color. -static u16 GetColorFromPersonality(u8 personality) -{ - u16 red = 0; - u16 green = 0; - u16 blue = 0; - u8 strength = (personality / 6) % 3; - u8 colorType = personality % 6; - - switch (colorType) - { - case 0: - // Teal color - green = 21 - strength; - blue = green; - red = 0; - break; - case 1: - // Yellow color - blue = 0; - red = 21 - strength; - green = red; - break; - case 2: - // Purple color - blue = 21 - strength; - green = 0; - red = blue; - break; - case 3: - // Red color - blue = 0; - green = 0; - red = 23 - strength; - break; - case 4: - // Blue color - blue = 23 - strength; - green = 0; - red = 0; - break; - case 5: - // Green color - blue = 0; - green = 23 - strength; - red = 0; - break; - } - - return RGB2(red, green, blue); -} - -static u16 QuantizePixel_BlackAndWhite(u16 *color) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - - if (red < 17 && green < 17 && blue < 17) - return RGB_BLACK; - else - return RGB_WHITE; -} - -static u16 QuantizePixel_BlackOutline(u16 *pixelA, u16 *pixelB) -{ - if (*pixelA != RGB_BLACK) - { - if (*pixelA & 0x8000) - return 0x8000; - if (*pixelB & 0x8000) - return RGB_BLACK; - - return *pixelA; - } - - return RGB_BLACK; -} - -static u16 QuantizePixel_Invert(u16 *color) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - - red = 31 - red; - green = 31 - green; - blue = 31 - blue; - - return RGB2(red, green, blue); -} - -static u16 QuantizePixel_MotionBlur(u16 *prevPixel, u16 *curPixel) -{ - u16 pixelChannels[2][3]; - u16 diffs[3]; - u8 i; - u16 largestDiff; - u16 red, green, blue; - - if (*prevPixel == *curPixel) - return *curPixel; - - pixelChannels[0][0] = (*prevPixel >> 0) & 0x1F; - pixelChannels[0][1] = (*prevPixel >> 5) & 0x1F; - pixelChannels[0][2] = (*prevPixel >> 10) & 0x1F; - pixelChannels[1][0] = (*curPixel >> 0) & 0x1F; - pixelChannels[1][1] = (*curPixel >> 5) & 0x1F; - pixelChannels[1][2] = (*curPixel >> 10) & 0x1F; - - // Don't blur light colors. - if (pixelChannels[0][0] > 25 && pixelChannels[0][1] > 25 && pixelChannels[0][2] > 25) - return *curPixel; - if (pixelChannels[1][0] > 25 && pixelChannels[1][1] > 25 && pixelChannels[1][2] > 25) - return *curPixel; - - for (i = 0; i < 3; i++) - { - if (pixelChannels[0][i] > pixelChannels[1][i]) - diffs[i] = pixelChannels[0][i] - pixelChannels[1][i]; - else - diffs[i] = pixelChannels[1][i] - pixelChannels[0][i]; - } - - // Find the largest diff of any of the color channels. - if (diffs[0] >= diffs[1]) - { - if (diffs[0] >= diffs[2]) - largestDiff = diffs[0]; - else if (diffs[1] >= diffs[2]) - largestDiff = diffs[1]; - else - largestDiff = diffs[2]; - } - else - { - if (diffs[1] >= diffs[2]) - largestDiff = diffs[1]; - else if (diffs[2] >= diffs[0]) - largestDiff = diffs[2]; - else - largestDiff = diffs[0]; - } - - red = (pixelChannels[1][0] * (31 - largestDiff / 2)) / 31; - green = (pixelChannels[1][1] * (31 - largestDiff / 2)) / 31; - blue = (pixelChannels[1][2] * (31 - largestDiff / 2)) / 31; - return RGB2(red, green, blue); -} - -static u16 QuantizePixel_Blur(u16 *prevPixel, u16 *curPixel, u16 *nextPixel) -{ - u16 red, green, blue; - u16 prevAvg, curAvg, nextAvg; - u16 prevDiff, nextDiff; - u32 diff; - u16 factor; - - if (*prevPixel == *curPixel && *nextPixel == *curPixel) - return *curPixel; - - red = (*curPixel >> 0) & 0x1F; - green = (*curPixel >> 5) & 0x1F; - blue = (*curPixel >> 10) & 0x1F; - - prevAvg = (((*prevPixel >> 0) & 0x1F) + ((*prevPixel >> 5) & 0x1F) + ((*prevPixel >> 10) & 0x1F)) / 3; - curAvg = (((*curPixel >> 0) & 0x1F) + ((*curPixel >> 5) & 0x1F) + ((*curPixel >> 10) & 0x1F)) / 3; - nextAvg = (((*nextPixel >> 0) & 0x1F) + ((*nextPixel >> 5) & 0x1F) + ((*nextPixel >> 10) & 0x1F)) / 3; - - if (prevAvg == curAvg && nextAvg == curAvg) - return *curPixel; - - if (prevAvg > curAvg) - prevDiff = prevAvg - curAvg; - else - prevDiff = curAvg - prevAvg; - - if (nextAvg > curAvg) - nextDiff = nextAvg - curAvg; - else - nextDiff = curAvg - nextAvg; - - if (prevDiff >= nextDiff) - diff = prevDiff; - else - diff = nextDiff; - - factor = 31 - diff / 2; - red = (red * factor) / 31; - green = (green * factor) / 31; - blue = (blue * factor) / 31; - return RGB2(red, green, blue); -} - -static u16 QuantizePixel_BlurHard(u16 *prevPixel, u16 *curPixel, u16 *nextPixel) -{ - u16 red, green, blue; - u16 prevAvg, curAvg, nextAvg; - u16 prevDiff, nextDiff; - u32 diff; - u16 factor; - - if (*prevPixel == *curPixel && *nextPixel == *curPixel) - return *curPixel; - - red = (*curPixel >> 0) & 0x1F; - green = (*curPixel >> 5) & 0x1F; - blue = (*curPixel >> 10) & 0x1F; - - prevAvg = (((*prevPixel >> 0) & 0x1F) + ((*prevPixel >> 5) & 0x1F) + ((*prevPixel >> 10) & 0x1F)) / 3; - curAvg = (((*curPixel >> 0) & 0x1F) + ((*curPixel >> 5) & 0x1F) + ((*curPixel >> 10) & 0x1F)) / 3; - nextAvg = (((*nextPixel >> 0) & 0x1F) + ((*nextPixel >> 5) & 0x1F) + ((*nextPixel >> 10) & 0x1F)) / 3; - - if (prevAvg == curAvg && nextAvg == curAvg) - return *curPixel; - - if (prevAvg > curAvg) - prevDiff = prevAvg - curAvg; - else - prevDiff = curAvg - prevAvg; - - if (nextAvg > curAvg) - nextDiff = nextAvg - curAvg; - else - nextDiff = curAvg - nextAvg; - - if (prevDiff >= nextDiff) - diff = prevDiff; - else - diff = nextDiff; - - factor = 31 - diff; - red = (red * factor) / 31; - green = (green * factor) / 31; - blue = (blue * factor) / 31; - return RGB2(red, green, blue); -} - -/* -void ConvertImageProcessingToGBA(struct ContestPaintingContext *arg0) -{ - u16 i, j, k; - u8 r5 = arg0->canvasWidth >> 3; - u8 var_24 = arg0->canvasHeight >> 3; - u16 (*var_2C)[][32] = arg0->canvasPixels; - u32 var_28 = arg0->dest; - - if (arg0->var_16 == 2) - { - for (i = 0; i < var_24; i++) - { - for (j = 0; j < r5; j++) - { - for (k = 0; k < 8; k++) - { - (*var_2C)[][]; - } - } - } - } -} -*/ - -NAKED -void ConvertImageProcessingToGBA(struct ContestPaintingContext *arg0) -{ - asm_unified("\n\ - push {r4-r7,lr}\n\ - mov r7, r10\n\ - mov r6, r9\n\ - mov r5, r8\n\ - push {r5-r7}\n\ - sub sp, 0xC\n\ - ldrb r1, [r0, 0x1D]\n\ - lsrs r5, r1, 3\n\ - ldrb r1, [r0, 0x1E]\n\ - lsrs r1, 3\n\ - str r1, [sp, 0x8]\n\ - ldr r1, [r0, 0x4]\n\ - str r1, [sp]\n\ - ldr r2, [r0, 0x10]\n\ - str r2, [sp, 0x4]\n\ - ldrh r0, [r0, 0x16]\n\ - cmp r0, 0x2\n\ - bne _08126108\n\ - movs r1, 0\n\ - ldr r0, [sp, 0x8]\n\ - cmp r1, r0\n\ - bcc _08126086\n\ - b _08126194\n\ -_08126086:\n\ - movs r0, 0\n\ - adds r2, r1, 0x1\n\ - mov r10, r2\n\ - cmp r0, r5\n\ - bcs _081260FA\n\ - adds r2, r1, 0\n\ - muls r2, r5\n\ - mov r9, r2\n\ - lsls r1, 3\n\ - mov r8, r1\n\ -_0812609A:\n\ - movs r4, 0\n\ - lsls r6, r0, 4\n\ - adds r7, r0, 0x1\n\ - add r0, r9\n\ - lsls r0, 6\n\ - ldr r1, [sp, 0x4]\n\ - adds r1, r0\n\ - mov r12, r1\n\ -_081260AA:\n\ - lsls r0, r4, 3\n\ - mov r2, r12\n\ - adds r3, r2, r0\n\ - mov r1, r8\n\ - adds r0, r1, r4\n\ - lsls r0, 3\n\ - muls r0, r5\n\ - lsls r0, 1\n\ - ldr r2, [sp]\n\ - adds r0, r2, r0\n\ - adds r2, r0, r6\n\ - ldrh r0, [r2, 0x2]\n\ - lsls r0, 8\n\ - ldrh r1, [r2]\n\ - orrs r0, r1\n\ - strh r0, [r3]\n\ - ldrh r0, [r2, 0x6]\n\ - lsls r0, 8\n\ - ldrh r1, [r2, 0x4]\n\ - orrs r0, r1\n\ - strh r0, [r3, 0x2]\n\ - ldrh r0, [r2, 0xA]\n\ - lsls r0, 8\n\ - ldrh r1, [r2, 0x8]\n\ - orrs r0, r1\n\ - strh r0, [r3, 0x4]\n\ - ldrh r0, [r2, 0xE]\n\ - lsls r0, 8\n\ - ldrh r1, [r2, 0xC]\n\ - orrs r0, r1\n\ - strh r0, [r3, 0x6]\n\ - adds r0, r4, 0x1\n\ - lsls r0, 16\n\ - lsrs r4, r0, 16\n\ - cmp r4, 0x7\n\ - bls _081260AA\n\ - lsls r0, r7, 16\n\ - lsrs r0, 16\n\ - cmp r0, r5\n\ - bcc _0812609A\n\ -_081260FA:\n\ - mov r1, r10\n\ - lsls r0, r1, 16\n\ - lsrs r1, r0, 16\n\ - ldr r2, [sp, 0x8]\n\ - cmp r1, r2\n\ - bcc _08126086\n\ - b _08126194\n\ -_08126108:\n\ - movs r1, 0\n\ - ldr r0, [sp, 0x8]\n\ - cmp r1, r0\n\ - bcs _08126194\n\ -_08126110:\n\ - movs r0, 0\n\ - adds r2, r1, 0x1\n\ - mov r10, r2\n\ - cmp r0, r5\n\ - bcs _08126188\n\ - adds r2, r1, 0\n\ - muls r2, r5\n\ - mov r9, r2\n\ - lsls r1, 3\n\ - mov r8, r1\n\ -_08126124:\n\ - movs r4, 0\n\ - lsls r6, r0, 4\n\ - adds r7, r0, 0x1\n\ - add r0, r9\n\ - lsls r0, 5\n\ - ldr r1, [sp, 0x4]\n\ - adds r1, r0\n\ - mov r12, r1\n\ -_08126134:\n\ - lsls r0, r4, 2\n\ - mov r2, r12\n\ - adds r3, r2, r0\n\ - mov r1, r8\n\ - adds r0, r1, r4\n\ - lsls r0, 3\n\ - muls r0, r5\n\ - lsls r0, 1\n\ - ldr r2, [sp]\n\ - adds r0, r2, r0\n\ - adds r2, r0, r6\n\ - ldrh r1, [r2, 0x2]\n\ - lsls r1, 4\n\ - ldrh r0, [r2]\n\ - orrs r1, r0\n\ - ldrh r0, [r2, 0x4]\n\ - lsls r0, 8\n\ - orrs r1, r0\n\ - ldrh r0, [r2, 0x6]\n\ - lsls r0, 12\n\ - orrs r1, r0\n\ - strh r1, [r3]\n\ - ldrh r1, [r2, 0xA]\n\ - lsls r1, 4\n\ - ldrh r0, [r2, 0x8]\n\ - orrs r1, r0\n\ - ldrh r0, [r2, 0xC]\n\ - lsls r0, 8\n\ - orrs r1, r0\n\ - ldrh r0, [r2, 0xE]\n\ - lsls r0, 12\n\ - orrs r1, r0\n\ - strh r1, [r3, 0x2]\n\ - adds r0, r4, 0x1\n\ - lsls r0, 16\n\ - lsrs r4, r0, 16\n\ - cmp r4, 0x7\n\ - bls _08126134\n\ - lsls r0, r7, 16\n\ - lsrs r0, 16\n\ - cmp r0, r5\n\ - bcc _08126124\n\ -_08126188:\n\ - mov r1, r10\n\ - lsls r0, r1, 16\n\ - lsrs r1, r0, 16\n\ - ldr r2, [sp, 0x8]\n\ - cmp r1, r2\n\ - bcc _08126110\n\ -_08126194:\n\ - add sp, 0xC\n\ - pop {r3-r5}\n\ - mov r8, r3\n\ - mov r9, r4\n\ - mov r10, r5\n\ - pop {r4-r7}\n\ - pop {r0}\n\ - bx r0"); -} - -void ApplyImageProcessingQuantization(struct ContestPaintingContext *context) -{ - gCanvasPaletteStart = context->paletteStart * 16; - gCanvasPalette = &context->canvasPalette[gCanvasPaletteStart]; - gCanvasPixels = context->canvasPixels; - gCanvasColumnStart = context->columnStart; - gCanvasRowStart = context->rowStart; - gCanvasColumnEnd = context->columnEnd; - gCanvasRowEnd = context->rowEnd; - gCanvasWidth = context->canvasWidth; - gCanvasHeight = context->canvasHeight; - - switch (context->quantizeEffect) - { - case QUANTIZE_EFFECT_STANDARD: - QuantizePalette_Standard(FALSE); - break; - case QUANTIZE_EFFECT_STANDARD_LIMITED_COLORS: - QuantizePalette_Standard(TRUE); - break; - case QUANTIZE_EFFECT_PRIMARY_COLORS: - SetPresetPalette_PrimaryColors(); - QuantizePalette_PrimaryColors(); - break; - case QUANTIZE_EFFECT_GRAYSCALE: - SetPresetPalette_Grayscale(); - QuantizePalette_Grayscale(); - break; - case QUANTIZE_EFFECT_GRAYSCALE_SMALL: - SetPresetPalette_GrayscaleSmall(); - QuantizePalette_GrayscaleSmall(); - break; - case QUANTIZE_EFFECT_BLACK_WHITE: - SetPresetPalette_BlackAndWhite(); - QuantizePalette_BlackAndWhite(); - break; - } -} - -static void SetPresetPalette_PrimaryColors(void) -{ - gCanvasPalette[0] = RGB2(0, 0, 0); - gCanvasPalette[1] = RGB2(6, 6, 6); - gCanvasPalette[2] = RGB2(29, 29, 29); - gCanvasPalette[3] = RGB2(11, 11, 11); - gCanvasPalette[4] = RGB2(29, 6, 6); - gCanvasPalette[5] = RGB2(6, 29, 6); - gCanvasPalette[6] = RGB2(6, 6, 29); - gCanvasPalette[7] = RGB2(29, 29, 6); - gCanvasPalette[8] = RGB2(29, 6, 29); - gCanvasPalette[9] = RGB2(6, 29, 29); - gCanvasPalette[10] = RGB2(29, 11, 6); - gCanvasPalette[11] = RGB2(11, 29, 6); - gCanvasPalette[12] = RGB2(6, 11, 29); - gCanvasPalette[13] = RGB2(29, 6, 11); - gCanvasPalette[14] = RGB2(6, 29, 11); - gCanvasPalette[15] = RGB2(11, 6, 29); -} - -static void SetPresetPalette_BlackAndWhite(void) -{ - gCanvasPalette[0] = RGB2(0, 0, 0); - gCanvasPalette[1] = RGB2(0, 0, 0); - gCanvasPalette[2] = RGB2(31, 31, 31); -} - -static void SetPresetPalette_GrayscaleSmall(void) -{ - u8 i; - - gCanvasPalette[0] = RGB2(0, 0, 0); - gCanvasPalette[1] = RGB2(0, 0, 0); - for (i = 0; i < 14; i++) - gCanvasPalette[i + 2] = RGB2(2 * (i + 2), 2 * (i + 2), 2 * (i + 2)); -} - -static void SetPresetPalette_Grayscale(void) -{ - u8 i; - - gCanvasPalette[0] = RGB2(0, 0, 0); - for (i = 0; i < 32; i++) - gCanvasPalette[i + 1] = RGB2(i, i, i); -} - -static void QuantizePalette_Standard(bool8 useLimitedPalette) -{ - u8 i, j; - u16 maxIndex; - - maxIndex = 0xDF; - if (!useLimitedPalette) - maxIndex = 0xFF; - - for (i = 0; i < maxIndex; i++) - gCanvasPalette[i] = RGB_BLACK; - - gCanvasPalette[maxIndex] = RGB2(15, 15, 15); - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (*pixel & 0x8000) - { - *pixel = gCanvasPaletteStart; - } - else - { - u16 quantizedColor = QuantizePixel_Standard(pixel); - u8 curIndex = 1; - if (curIndex < maxIndex) - { - if (gCanvasPalette[curIndex] == RGB_BLACK) - { - // The quantized color does not match any existing color in the - // palette, so we add it to the palette. - // This if block seems pointless because the below while loop handles - // this same logic. - gCanvasPalette[curIndex] = quantizedColor; - *pixel = gCanvasPaletteStart + curIndex; - } - else - { - while (curIndex < maxIndex) - { - if (gCanvasPalette[curIndex] == RGB_BLACK) - { - // The quantized color does not match any existing color in the - // palette, so we add it to the palette. - gCanvasPalette[curIndex] = quantizedColor; - *pixel = gCanvasPaletteStart + curIndex; - break; - } - - if (gCanvasPalette[curIndex] == quantizedColor) - { - // The quantized color matches this existing color in the - // palette, so we use this existing color for the pixel. - *pixel = gCanvasPaletteStart + curIndex; - break; - } - - curIndex++; - } - } - } - - if (curIndex == maxIndex) - { - // The entire palette's colors are already in use, which means - // the base image has too many colors to handle. This error is handled - // by marking such pixels as gray color. - curIndex = maxIndex; - *pixel = curIndex; - } - } - } - } -} - -static void QuantizePalette_BlackAndWhite(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (*pixel & 0x8000) - { - *pixel = gCanvasPaletteStart; - } - else - { - if (QuantizePixel_BlackAndWhite(pixel) == RGB_BLACK) - { - // Black is the first color in the quantized palette. - *pixel = gCanvasPaletteStart + 1; - } - else - { - // White is the second color in the quantized palette. - *pixel = gCanvasPaletteStart + 2; - } - } - } - } -} - -static void QuantizePalette_GrayscaleSmall(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (*pixel & 0x8000) - *pixel = gCanvasPaletteStart; - else - *pixel = QuantizePixel_GrayscaleSmall(pixel) + gCanvasPaletteStart; - } - } -} - -static void QuantizePalette_Grayscale(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (*pixel & 0x8000) - *pixel = gCanvasPaletteStart; - else - *pixel = QuantizePixel_Grayscale(pixel) + gCanvasPaletteStart; - } - } -} - -static void QuantizePalette_PrimaryColors(void) -{ - u8 i, j; - - for (j = 0; j < gCanvasRowEnd; j++) - { - u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; - u16 *pixel = &pixelRow[gCanvasColumnStart]; - for (i = 0; i < gCanvasColumnEnd; i++, pixel++) - { - if (*pixel & 0x8000) - *pixel = gCanvasPaletteStart; - else - *pixel = QuantizePixel_PrimaryColors(pixel) + gCanvasPaletteStart; - } - } -} - -// Quantizes the pixel's color channels to nearest multiple of 4, and clamps to [6, 30]. -static u16 QuantizePixel_Standard(u16 *pixel) -{ - u16 red = *pixel & 0x1F; - u16 green = (*pixel >> 5) & 0x1F; - u16 blue = (*pixel >> 10) & 0x1F; - - // Quantize color channels to muliples of 4, rounding up. - if (red & 3) - red = (red & 0x1C) + 4; - if (green & 3) - green = (green & 0x1C) + 4; - if (blue & 3) - blue = (blue & 0x1C) + 4; - - // Clamp channels to [6, 30]. - if (red < 6) - red = 6; - if (red > 30) - red = 30; - if (green < 6) - green = 6; - if (green > 30) - green = 30; - if (blue < 6) - blue = 6; - if (blue > 30) - blue = 30; - - return RGB2(red, green, blue); -} - -static u16 QuantizePixel_PrimaryColors(u16* color) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - - if (red < 12 && green < 11 && blue < 11) - return 1; - - if (red > 19 && green > 19 && blue > 19) - return 2; - - if (red > 19) - { - if (green > 19) - { - if (blue > 14) - return 2; - else - return 7; - } - else if (blue > 19) - { - if (green > 14) - return 2; - else - return 8; - } - } - - if (green > 19 && blue > 19) - { - if (red > 14) - return 2; - else - return 9; - } - - if (red > 19) - { - if (green > 11) - { - if (blue > 11) - { - if (green < blue) - return 8; - else - return 7; - } - else - { - return 10; - } - } - else if (blue > 11) - { - return 13; - } - else - { - return 4; - } - } - - if (green > 19) - { - if (red > 11) - { - if (blue > 11) - { - if (red < blue) - return 9; - else - return 7; - } - else - { - return 11; - } - } - else - { - if (blue > 11) - return 14; - else - return 5; - } - } - - if (blue > 19) - { - if (red > 11) - { - if (green > 11) - { - if (red < green) - return 9; - else - return 8; - } - } - else if (green > 11) - { - return 12; - } - - if (blue > 11) - return 15; - else - return 6; - } - - return 3; -} - -static u16 QuantizePixel_GrayscaleSmall(u16 *color) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - u16 average = ((red + green + blue) / 3) & 0x1E; - if (average == 0) - return 1; - else - return average / 2; -} - -static u16 QuantizePixel_Grayscale(u16 *color) -{ - u16 red = *color & 0x1F; - u16 green = (*color >> 5) & 0x1F; - u16 blue = (*color >> 10) & 0x1F; - u16 average = (red + green + blue) / 3; - return average + 1; -} diff --git a/src/image_processing_effects.c b/src/image_processing_effects.c new file mode 100644 index 000000000..c12305474 --- /dev/null +++ b/src/image_processing_effects.c @@ -0,0 +1,1384 @@ +#include "global.h" +#include "image_processing_effects.h" +#include "contest_painting.h" +#include "constants/rgb.h" + +// IWRAM common +u8 gCanvasColumnStart; +u16 (*gCanvasPixels)[][32]; +u8 gCanvasRowEnd; +u8 gCanvasHeight; +u8 gCanvasColumnEnd; +u8 gCanvasRowStart; +u8 gCanvasMonPersonality; +u8 gCanvasWidth; +u16 *gCanvasPalette; +u16 gCanvasPaletteStart; + +static void ApplyImageEffect_Pointillism(void); +static void ApplyImageEffect_Blur(void); +static void ApplyImageEffect_BlackOutline(void); +static void ApplyImageEffect_Invert(void); +static void ApplyImageEffect_BlackAndWhite(void); +static void ApplyImageEffect_BlurRight(void); +static void ApplyImageEffect_BlurDown(void); +static void ApplyImageEffect_Shimmer(void); +static void ApplyImageEffect_Grayscale(void); +static void ApplyImageEffect_PersonalityColor(u8); +static void ApplyImageEffect_RedChannelGrayscale(u8); +static void ApplyImageEffect_RedChannelGrayscaleHighlight(u8); +static void AddPointillismPoints(u16); +static u16 ConvertColorToGrayscale(u16*); +static u16 QuantizePixel_Blur(u16*, u16*, u16*); +static u16 QuantizePixel_PersonalityColor(u16*, u8); +static u16 QuantizePixel_BlackAndWhite(u16*); +static u16 QuantizePixel_BlackOutline(u16*, u16*); +static u16 QuantizePixel_Invert(u16*); +static u16 QuantizePixel_BlurHard(u16*, u16*, u16*); +static u16 QuantizePixel_MotionBlur(u16*, u16*); +static u16 GetColorFromPersonality(u8); +static void QuantizePalette_Standard(bool8); +static void SetPresetPalette_PrimaryColors(void); +static void QuantizePalette_PrimaryColors(void); +static void SetPresetPalette_Grayscale(void); +static void QuantizePalette_Grayscale(void); +static void SetPresetPalette_GrayscaleSmall(void); +static void QuantizePalette_GrayscaleSmall(void); +static void SetPresetPalette_BlackAndWhite(void); +static void QuantizePalette_BlackAndWhite(void); +static u16 QuantizePixel_Standard(u16*); +static u16 QuantizePixel_GrayscaleSmall(u16*); +static u16 QuantizePixel_Grayscale(u16*); +static u16 QuantizePixel_PrimaryColors(u16*); + +extern const u8 gPointillismPoints[][3]; + +void ApplyImageProcessingEffects(struct ImageProcessingContext *context) +{ + gCanvasPixels = context->canvasPixels; + gCanvasMonPersonality = context->personality; + gCanvasColumnStart = context->columnStart; + gCanvasRowStart = context->rowStart; + gCanvasColumnEnd = context->columnEnd; + gCanvasRowEnd = context->rowEnd; + gCanvasWidth = context->canvasWidth; + gCanvasHeight = context->canvasHeight; + + switch (context->effect) + { + case IMAGE_EFFECT_POINTILLISM: + ApplyImageEffect_Pointillism(); + break; + case IMAGE_EFFECT_BLUR: + ApplyImageEffect_Blur(); + break; + case IMAGE_EFFECT_OUTLINE_COLORED: + ApplyImageEffect_BlackOutline(); + ApplyImageEffect_PersonalityColor(gCanvasMonPersonality); + break; + case IMAGE_EFFECT_INVERT_BLACK_WHITE: + ApplyImageEffect_BlackOutline(); + ApplyImageEffect_Invert(); + ApplyImageEffect_BlackAndWhite(); + case IMAGE_EFFECT_INVERT: + ApplyImageEffect_Invert(); + break; + case IMAGE_EFFECT_THICK_BLACK_WHITE: + ApplyImageEffect_BlackOutline(); + ApplyImageEffect_BlurRight(); + ApplyImageEffect_BlurRight(); + ApplyImageEffect_BlurDown(); + ApplyImageEffect_BlackAndWhite(); + break; + case IMAGE_EFFECT_SHIMMER: + ApplyImageEffect_Shimmer(); + break; + case IMAGE_EFFECT_OUTLINE: + ApplyImageEffect_BlackOutline(); + break; + case IMAGE_EFFECT_BLUR_RIGHT: + ApplyImageEffect_BlurRight(); + break; + case IMAGE_EFFECT_BLUR_DOWN: + ApplyImageEffect_BlurDown(); + break; + case IMAGE_EFFECT_GRAYSCALE_LIGHT: + ApplyImageEffect_Grayscale(); + ApplyImageEffect_RedChannelGrayscale(3); + break; + case IMAGE_EFFECT_CHARCOAL: + ApplyImageEffect_BlackOutline(); + ApplyImageEffect_BlurRight(); + ApplyImageEffect_BlurDown(); + ApplyImageEffect_BlackAndWhite(); + ApplyImageEffect_Blur(); + ApplyImageEffect_Blur(); + ApplyImageEffect_RedChannelGrayscale(2); + ApplyImageEffect_RedChannelGrayscaleHighlight(4); + break; + } +} + +static void ApplyImageEffect_RedChannelGrayscale(u8 delta) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + { + // Gets the grayscale value, based on the pixel's red channel. + // Also adds a delta to skew lighter or darker. + u8 grayValue = (31 & *pixel); + grayValue += delta; + if (grayValue > 31) + grayValue = 31; + + *pixel = RGB2(grayValue, grayValue, grayValue); + } + } + } +} + +static void ApplyImageEffect_RedChannelGrayscaleHighlight(u8 highlight) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + { + u8 grayValue = (31 & *pixel); + if (grayValue > 31 - highlight) + grayValue = 31 - (highlight >> 1); + + *pixel = RGB2(grayValue, grayValue, grayValue); + } + } + } +} + +static void ApplyImageEffect_Pointillism(void) +{ + u32 i; + for (i = 0; i < 3200; i++) + AddPointillismPoints(i); +} + +static void ApplyImageEffect_Grayscale(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = ConvertColorToGrayscale(pixel); + } + } +} + +static void ApplyImageEffect_Blur(void) +{ + u8 i, j; + + for (i = 0; i < gCanvasColumnEnd; i++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart + i]; + u16 prevPixel = *pixel; + + j = 1; + pixel += gCanvasWidth; + while (j < gCanvasRowEnd - 1) + { + if (!(0x8000 & *pixel)) + { + *pixel = QuantizePixel_Blur(&prevPixel, pixel, pixel + gCanvasWidth); + prevPixel = *pixel; + } + + j++; + pixel += gCanvasWidth; + } + } +} + +static void ApplyImageEffect_PersonalityColor(u8 personality) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = QuantizePixel_PersonalityColor(pixel, personality); + } + } +} + +static void ApplyImageEffect_BlackAndWhite(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = QuantizePixel_BlackAndWhite(pixel); + } + } +} + +static void ApplyImageEffect_BlackOutline(void) +{ + u8 i, j; + u16 *pixel; + + // Handle top row of pixels first. + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + pixel = &pixelRow[gCanvasColumnStart]; + *pixel = QuantizePixel_BlackOutline(pixel, pixel + 1); + for (i = 1, pixel++; i < gCanvasColumnEnd - 1; i++, pixel++) + { + *pixel = QuantizePixel_BlackOutline(pixel, pixel + 1); + *pixel = QuantizePixel_BlackOutline(pixel, pixel - 1); + } + + *pixel = QuantizePixel_BlackOutline(pixel, pixel - 1); + } + + // Handle each column from left to right. + for (i = 0; i < gCanvasColumnEnd; i++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; + pixel = &pixelRow[gCanvasColumnStart + i]; + *pixel = QuantizePixel_BlackOutline(pixel, pixel + gCanvasWidth); + for (j = 1, pixel += gCanvasWidth; j < gCanvasRowEnd - 1; j++, pixel += gCanvasWidth) + { + *pixel = QuantizePixel_BlackOutline(pixel, pixel + gCanvasWidth); + *pixel = QuantizePixel_BlackOutline(pixel, pixel - gCanvasWidth); + } + + *pixel = QuantizePixel_BlackOutline(pixel, pixel - gCanvasWidth); + } +} + +static void ApplyImageEffect_Invert(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = QuantizePixel_Invert(pixel); + } + } +} + +static void ApplyImageEffect_Shimmer(void) +{ + u8 i, j; + u16 *pixel; + u16 prevPixel; + + // First, invert all of the colors. + pixel = (*gCanvasPixels)[0]; + for (i = 0; i < 64; i++) + { + for (j = 0; j < 64; j++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = QuantizePixel_Invert(pixel); + } + } + + // Blur the pixels twice. + for (j = 0; j < 64; j++) + { + pixel = &(*gCanvasPixels)[0][j]; + prevPixel = *pixel; + *pixel = 0x8000; + for (i = 1, pixel += 64; i < 63; i++, pixel += 64) + { + if (!(0x8000 & *pixel)) + { + *pixel = QuantizePixel_BlurHard(&prevPixel, pixel, pixel + 64); + prevPixel = *pixel; + } + } + + *pixel = 0x8000; + pixel = &(*gCanvasPixels)[0][j]; + prevPixel = *pixel; + *pixel = 0x8000; + for (i = 1, pixel += 64; i < 63; i++, pixel += 64) + { + if (!(0x8000 & *pixel)) + { + *pixel = QuantizePixel_BlurHard(&prevPixel, pixel, pixel + 64); + prevPixel = *pixel; + } + } + + *pixel = 0x8000; + } + + // Finally, invert colors back to the original color space. + // The above blur causes the outline areas to darken, which makes + // this inversion give the effect of light outlines. + pixel = (*gCanvasPixels)[0]; + for (i = 0; i < 64; i++) + { + for (j = 0; j < 64; j++, pixel++) + { + if (!(0x8000 & *pixel)) + *pixel = QuantizePixel_Invert(pixel); + } + } +} + +static void ApplyImageEffect_BlurRight(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + u16 prevPixel = *pixel; + for (i = 1, pixel++; i < gCanvasColumnEnd - 1; i++, pixel++) + { + if (!(0x8000 & *pixel)) + { + *pixel = QuantizePixel_MotionBlur(&prevPixel, pixel); + prevPixel = *pixel; + } + } + } +} + +static void ApplyImageEffect_BlurDown(void) +{ + u8 i, j; + + for (i = 0; i < gCanvasColumnEnd; i++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][gCanvasRowStart * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart + i]; + u16 prevPixel = *pixel; + for (j = 1, pixel += gCanvasWidth; j < gCanvasRowEnd - 1; j++, pixel += gCanvasWidth) + { + if (!(0x8000 & *pixel)) + { + *pixel = QuantizePixel_MotionBlur(&prevPixel, pixel); + prevPixel = *pixel; + } + } + } +} + +struct PointillismPoint +{ + u8 column; + u8 row; + u16 delta; +}; + +static void AddPointillismPoints(u16 arg0) +{ + u8 i; + bool8 offsetDownLeft; + u8 colorType; + struct PointillismPoint points[6]; + + points[0].column = gPointillismPoints[arg0][0]; + points[0].row = gPointillismPoints[arg0][1]; + points[0].delta = (gPointillismPoints[arg0][2] >> 3) & 7; + + colorType = (gPointillismPoints[arg0][2] >> 1) & 3; + offsetDownLeft = gPointillismPoints[arg0][2] & 1; + for (i = 1; i < points[0].delta; i++) + { + if (!offsetDownLeft) + { + points[i].column = points[0].column - i; + points[i].row = points[0].row + i; + } + else + { + points[i].column = points[0].column + 1; + points[i].row = points[0].row - 1; + } + + if (points[i].column > 63 || points[i].row > 63) + { + points[0].delta = i - 1; + break; + } + + points[i].delta = points[0].delta - i; + } + + for (i = 0; i < points[0].delta; i++) + { + u16 *pixel = &(*gCanvasPixels)[points[i].row * 2][points[i].column]; + + if (!(0x8000 & *pixel)) + { + u16 red = (*pixel) & 0x1F; + u16 green = (*pixel >> 5) & 0x1F; + u16 blue = (*pixel >> 10) & 0x1F; + + switch (colorType) + { + case 0: + case 1: + switch (((gPointillismPoints[arg0][2] >> 3) & 7) % 3) + { + case 0: + if (red >= points[i].delta) + red -= points[i].delta; + else + red = 0; + break; + case 1: + if (green >= points[i].delta) + green -= points[i].delta; + else + green = 0; + break; + case 2: + if (blue >= points[i].delta) + blue -= points[i].delta; + else + blue = 0; + break; + } + break; + case 2: + case 3: + red += points[i].delta; + green += points[i].delta; + blue += points[i].delta; + if (red > 31) + red = 31; + if (green > 31) + green = 31; + if (blue > 31) + blue = 31; + break; + } + + *pixel = RGB2(red, green, blue); + } + } +} + +static u16 ConvertColorToGrayscale(u16 *color) +{ + s32 clr = *color; + s32 r = clr & 0x1F; + s32 g = (clr >> 5) & 0x1F; + s32 b = (clr >> 10) & 0x1F; + s32 gray = (r * Q_8_8(0.3) + g * Q_8_8(0.59) + b * Q_8_8(0.1133)) >> 8; + return RGB2(gray, gray, gray); +} + +// The dark colors are the colored edges of the Cool painting effect. +// Everything else is white. +static u16 QuantizePixel_PersonalityColor(u16 *color, u8 personality) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + + if (red < 17 && green < 17 && blue < 17) + return GetColorFromPersonality(personality); + else + return RGB_WHITE; +} + +// Based on the given value, which comes from the first 8 bits of +// the mon's personality value, return a color. +static u16 GetColorFromPersonality(u8 personality) +{ + u16 red = 0; + u16 green = 0; + u16 blue = 0; + u8 strength = (personality / 6) % 3; + u8 colorType = personality % 6; + + switch (colorType) + { + case 0: + // Teal color + green = 21 - strength; + blue = green; + red = 0; + break; + case 1: + // Yellow color + blue = 0; + red = 21 - strength; + green = red; + break; + case 2: + // Purple color + blue = 21 - strength; + green = 0; + red = blue; + break; + case 3: + // Red color + blue = 0; + green = 0; + red = 23 - strength; + break; + case 4: + // Blue color + blue = 23 - strength; + green = 0; + red = 0; + break; + case 5: + // Green color + blue = 0; + green = 23 - strength; + red = 0; + break; + } + + return RGB2(red, green, blue); +} + +static u16 QuantizePixel_BlackAndWhite(u16 *color) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + + if (red < 17 && green < 17 && blue < 17) + return RGB_BLACK; + else + return RGB_WHITE; +} + +static u16 QuantizePixel_BlackOutline(u16 *pixelA, u16 *pixelB) +{ + if (*pixelA != RGB_BLACK) + { + if (*pixelA & 0x8000) + return 0x8000; + if (*pixelB & 0x8000) + return RGB_BLACK; + + return *pixelA; + } + + return RGB_BLACK; +} + +static u16 QuantizePixel_Invert(u16 *color) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + + red = 31 - red; + green = 31 - green; + blue = 31 - blue; + + return RGB2(red, green, blue); +} + +static u16 QuantizePixel_MotionBlur(u16 *prevPixel, u16 *curPixel) +{ + u16 pixelChannels[2][3]; + u16 diffs[3]; + u8 i; + u16 largestDiff; + u16 red, green, blue; + + if (*prevPixel == *curPixel) + return *curPixel; + + pixelChannels[0][0] = (*prevPixel >> 0) & 0x1F; + pixelChannels[0][1] = (*prevPixel >> 5) & 0x1F; + pixelChannels[0][2] = (*prevPixel >> 10) & 0x1F; + pixelChannels[1][0] = (*curPixel >> 0) & 0x1F; + pixelChannels[1][1] = (*curPixel >> 5) & 0x1F; + pixelChannels[1][2] = (*curPixel >> 10) & 0x1F; + + // Don't blur light colors. + if (pixelChannels[0][0] > 25 && pixelChannels[0][1] > 25 && pixelChannels[0][2] > 25) + return *curPixel; + if (pixelChannels[1][0] > 25 && pixelChannels[1][1] > 25 && pixelChannels[1][2] > 25) + return *curPixel; + + for (i = 0; i < 3; i++) + { + if (pixelChannels[0][i] > pixelChannels[1][i]) + diffs[i] = pixelChannels[0][i] - pixelChannels[1][i]; + else + diffs[i] = pixelChannels[1][i] - pixelChannels[0][i]; + } + + // Find the largest diff of any of the color channels. + if (diffs[0] >= diffs[1]) + { + if (diffs[0] >= diffs[2]) + largestDiff = diffs[0]; + else if (diffs[1] >= diffs[2]) + largestDiff = diffs[1]; + else + largestDiff = diffs[2]; + } + else + { + if (diffs[1] >= diffs[2]) + largestDiff = diffs[1]; + else if (diffs[2] >= diffs[0]) + largestDiff = diffs[2]; + else + largestDiff = diffs[0]; + } + + red = (pixelChannels[1][0] * (31 - largestDiff / 2)) / 31; + green = (pixelChannels[1][1] * (31 - largestDiff / 2)) / 31; + blue = (pixelChannels[1][2] * (31 - largestDiff / 2)) / 31; + return RGB2(red, green, blue); +} + +static u16 QuantizePixel_Blur(u16 *prevPixel, u16 *curPixel, u16 *nextPixel) +{ + u16 red, green, blue; + u16 prevAvg, curAvg, nextAvg; + u16 prevDiff, nextDiff; + u32 diff; + u16 factor; + + if (*prevPixel == *curPixel && *nextPixel == *curPixel) + return *curPixel; + + red = (*curPixel >> 0) & 0x1F; + green = (*curPixel >> 5) & 0x1F; + blue = (*curPixel >> 10) & 0x1F; + + prevAvg = (((*prevPixel >> 0) & 0x1F) + ((*prevPixel >> 5) & 0x1F) + ((*prevPixel >> 10) & 0x1F)) / 3; + curAvg = (((*curPixel >> 0) & 0x1F) + ((*curPixel >> 5) & 0x1F) + ((*curPixel >> 10) & 0x1F)) / 3; + nextAvg = (((*nextPixel >> 0) & 0x1F) + ((*nextPixel >> 5) & 0x1F) + ((*nextPixel >> 10) & 0x1F)) / 3; + + if (prevAvg == curAvg && nextAvg == curAvg) + return *curPixel; + + if (prevAvg > curAvg) + prevDiff = prevAvg - curAvg; + else + prevDiff = curAvg - prevAvg; + + if (nextAvg > curAvg) + nextDiff = nextAvg - curAvg; + else + nextDiff = curAvg - nextAvg; + + if (prevDiff >= nextDiff) + diff = prevDiff; + else + diff = nextDiff; + + factor = 31 - diff / 2; + red = (red * factor) / 31; + green = (green * factor) / 31; + blue = (blue * factor) / 31; + return RGB2(red, green, blue); +} + +static u16 QuantizePixel_BlurHard(u16 *prevPixel, u16 *curPixel, u16 *nextPixel) +{ + u16 red, green, blue; + u16 prevAvg, curAvg, nextAvg; + u16 prevDiff, nextDiff; + u32 diff; + u16 factor; + + if (*prevPixel == *curPixel && *nextPixel == *curPixel) + return *curPixel; + + red = (*curPixel >> 0) & 0x1F; + green = (*curPixel >> 5) & 0x1F; + blue = (*curPixel >> 10) & 0x1F; + + prevAvg = (((*prevPixel >> 0) & 0x1F) + ((*prevPixel >> 5) & 0x1F) + ((*prevPixel >> 10) & 0x1F)) / 3; + curAvg = (((*curPixel >> 0) & 0x1F) + ((*curPixel >> 5) & 0x1F) + ((*curPixel >> 10) & 0x1F)) / 3; + nextAvg = (((*nextPixel >> 0) & 0x1F) + ((*nextPixel >> 5) & 0x1F) + ((*nextPixel >> 10) & 0x1F)) / 3; + + if (prevAvg == curAvg && nextAvg == curAvg) + return *curPixel; + + if (prevAvg > curAvg) + prevDiff = prevAvg - curAvg; + else + prevDiff = curAvg - prevAvg; + + if (nextAvg > curAvg) + nextDiff = nextAvg - curAvg; + else + nextDiff = curAvg - nextAvg; + + if (prevDiff >= nextDiff) + diff = prevDiff; + else + diff = nextDiff; + + factor = 31 - diff; + red = (red * factor) / 31; + green = (green * factor) / 31; + blue = (blue * factor) / 31; + return RGB2(red, green, blue); +} + +/* +void ConvertImageProcessingToGBA(struct ImageProcessingContext *arg0) +{ + u16 i, j, k; + u8 r5 = arg0->canvasWidth >> 3; + u8 var_24 = arg0->canvasHeight >> 3; + u16 (*var_2C)[][32] = arg0->canvasPixels; + u32 var_28 = arg0->dest; + + if (arg0->var_16 == 2) + { + for (i = 0; i < var_24; i++) + { + for (j = 0; j < r5; j++) + { + for (k = 0; k < 8; k++) + { + (*var_2C)[][]; + } + } + } + } +} +*/ + +NAKED +void ConvertImageProcessingToGBA(struct ImageProcessingContext *arg0) +{ + asm_unified("\n\ + push {r4-r7,lr}\n\ + mov r7, r10\n\ + mov r6, r9\n\ + mov r5, r8\n\ + push {r5-r7}\n\ + sub sp, 0xC\n\ + ldrb r1, [r0, 0x1D]\n\ + lsrs r5, r1, 3\n\ + ldrb r1, [r0, 0x1E]\n\ + lsrs r1, 3\n\ + str r1, [sp, 0x8]\n\ + ldr r1, [r0, 0x4]\n\ + str r1, [sp]\n\ + ldr r2, [r0, 0x10]\n\ + str r2, [sp, 0x4]\n\ + ldrh r0, [r0, 0x16]\n\ + cmp r0, 0x2\n\ + bne _08126108\n\ + movs r1, 0\n\ + ldr r0, [sp, 0x8]\n\ + cmp r1, r0\n\ + bcc _08126086\n\ + b _08126194\n\ +_08126086:\n\ + movs r0, 0\n\ + adds r2, r1, 0x1\n\ + mov r10, r2\n\ + cmp r0, r5\n\ + bcs _081260FA\n\ + adds r2, r1, 0\n\ + muls r2, r5\n\ + mov r9, r2\n\ + lsls r1, 3\n\ + mov r8, r1\n\ +_0812609A:\n\ + movs r4, 0\n\ + lsls r6, r0, 4\n\ + adds r7, r0, 0x1\n\ + add r0, r9\n\ + lsls r0, 6\n\ + ldr r1, [sp, 0x4]\n\ + adds r1, r0\n\ + mov r12, r1\n\ +_081260AA:\n\ + lsls r0, r4, 3\n\ + mov r2, r12\n\ + adds r3, r2, r0\n\ + mov r1, r8\n\ + adds r0, r1, r4\n\ + lsls r0, 3\n\ + muls r0, r5\n\ + lsls r0, 1\n\ + ldr r2, [sp]\n\ + adds r0, r2, r0\n\ + adds r2, r0, r6\n\ + ldrh r0, [r2, 0x2]\n\ + lsls r0, 8\n\ + ldrh r1, [r2]\n\ + orrs r0, r1\n\ + strh r0, [r3]\n\ + ldrh r0, [r2, 0x6]\n\ + lsls r0, 8\n\ + ldrh r1, [r2, 0x4]\n\ + orrs r0, r1\n\ + strh r0, [r3, 0x2]\n\ + ldrh r0, [r2, 0xA]\n\ + lsls r0, 8\n\ + ldrh r1, [r2, 0x8]\n\ + orrs r0, r1\n\ + strh r0, [r3, 0x4]\n\ + ldrh r0, [r2, 0xE]\n\ + lsls r0, 8\n\ + ldrh r1, [r2, 0xC]\n\ + orrs r0, r1\n\ + strh r0, [r3, 0x6]\n\ + adds r0, r4, 0x1\n\ + lsls r0, 16\n\ + lsrs r4, r0, 16\n\ + cmp r4, 0x7\n\ + bls _081260AA\n\ + lsls r0, r7, 16\n\ + lsrs r0, 16\n\ + cmp r0, r5\n\ + bcc _0812609A\n\ +_081260FA:\n\ + mov r1, r10\n\ + lsls r0, r1, 16\n\ + lsrs r1, r0, 16\n\ + ldr r2, [sp, 0x8]\n\ + cmp r1, r2\n\ + bcc _08126086\n\ + b _08126194\n\ +_08126108:\n\ + movs r1, 0\n\ + ldr r0, [sp, 0x8]\n\ + cmp r1, r0\n\ + bcs _08126194\n\ +_08126110:\n\ + movs r0, 0\n\ + adds r2, r1, 0x1\n\ + mov r10, r2\n\ + cmp r0, r5\n\ + bcs _08126188\n\ + adds r2, r1, 0\n\ + muls r2, r5\n\ + mov r9, r2\n\ + lsls r1, 3\n\ + mov r8, r1\n\ +_08126124:\n\ + movs r4, 0\n\ + lsls r6, r0, 4\n\ + adds r7, r0, 0x1\n\ + add r0, r9\n\ + lsls r0, 5\n\ + ldr r1, [sp, 0x4]\n\ + adds r1, r0\n\ + mov r12, r1\n\ +_08126134:\n\ + lsls r0, r4, 2\n\ + mov r2, r12\n\ + adds r3, r2, r0\n\ + mov r1, r8\n\ + adds r0, r1, r4\n\ + lsls r0, 3\n\ + muls r0, r5\n\ + lsls r0, 1\n\ + ldr r2, [sp]\n\ + adds r0, r2, r0\n\ + adds r2, r0, r6\n\ + ldrh r1, [r2, 0x2]\n\ + lsls r1, 4\n\ + ldrh r0, [r2]\n\ + orrs r1, r0\n\ + ldrh r0, [r2, 0x4]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrh r0, [r2, 0x6]\n\ + lsls r0, 12\n\ + orrs r1, r0\n\ + strh r1, [r3]\n\ + ldrh r1, [r2, 0xA]\n\ + lsls r1, 4\n\ + ldrh r0, [r2, 0x8]\n\ + orrs r1, r0\n\ + ldrh r0, [r2, 0xC]\n\ + lsls r0, 8\n\ + orrs r1, r0\n\ + ldrh r0, [r2, 0xE]\n\ + lsls r0, 12\n\ + orrs r1, r0\n\ + strh r1, [r3, 0x2]\n\ + adds r0, r4, 0x1\n\ + lsls r0, 16\n\ + lsrs r4, r0, 16\n\ + cmp r4, 0x7\n\ + bls _08126134\n\ + lsls r0, r7, 16\n\ + lsrs r0, 16\n\ + cmp r0, r5\n\ + bcc _08126124\n\ +_08126188:\n\ + mov r1, r10\n\ + lsls r0, r1, 16\n\ + lsrs r1, r0, 16\n\ + ldr r2, [sp, 0x8]\n\ + cmp r1, r2\n\ + bcc _08126110\n\ +_08126194:\n\ + add sp, 0xC\n\ + pop {r3-r5}\n\ + mov r8, r3\n\ + mov r9, r4\n\ + mov r10, r5\n\ + pop {r4-r7}\n\ + pop {r0}\n\ + bx r0"); +} + +void ApplyImageProcessingQuantization(struct ImageProcessingContext *context) +{ + gCanvasPaletteStart = context->paletteStart * 16; + gCanvasPalette = &context->canvasPalette[gCanvasPaletteStart]; + gCanvasPixels = context->canvasPixels; + gCanvasColumnStart = context->columnStart; + gCanvasRowStart = context->rowStart; + gCanvasColumnEnd = context->columnEnd; + gCanvasRowEnd = context->rowEnd; + gCanvasWidth = context->canvasWidth; + gCanvasHeight = context->canvasHeight; + + switch (context->quantizeEffect) + { + case QUANTIZE_EFFECT_STANDARD: + QuantizePalette_Standard(FALSE); + break; + case QUANTIZE_EFFECT_STANDARD_LIMITED_COLORS: + QuantizePalette_Standard(TRUE); + break; + case QUANTIZE_EFFECT_PRIMARY_COLORS: + SetPresetPalette_PrimaryColors(); + QuantizePalette_PrimaryColors(); + break; + case QUANTIZE_EFFECT_GRAYSCALE: + SetPresetPalette_Grayscale(); + QuantizePalette_Grayscale(); + break; + case QUANTIZE_EFFECT_GRAYSCALE_SMALL: + SetPresetPalette_GrayscaleSmall(); + QuantizePalette_GrayscaleSmall(); + break; + case QUANTIZE_EFFECT_BLACK_WHITE: + SetPresetPalette_BlackAndWhite(); + QuantizePalette_BlackAndWhite(); + break; + } +} + +static void SetPresetPalette_PrimaryColors(void) +{ + gCanvasPalette[0] = RGB2(0, 0, 0); + gCanvasPalette[1] = RGB2(6, 6, 6); + gCanvasPalette[2] = RGB2(29, 29, 29); + gCanvasPalette[3] = RGB2(11, 11, 11); + gCanvasPalette[4] = RGB2(29, 6, 6); + gCanvasPalette[5] = RGB2(6, 29, 6); + gCanvasPalette[6] = RGB2(6, 6, 29); + gCanvasPalette[7] = RGB2(29, 29, 6); + gCanvasPalette[8] = RGB2(29, 6, 29); + gCanvasPalette[9] = RGB2(6, 29, 29); + gCanvasPalette[10] = RGB2(29, 11, 6); + gCanvasPalette[11] = RGB2(11, 29, 6); + gCanvasPalette[12] = RGB2(6, 11, 29); + gCanvasPalette[13] = RGB2(29, 6, 11); + gCanvasPalette[14] = RGB2(6, 29, 11); + gCanvasPalette[15] = RGB2(11, 6, 29); +} + +static void SetPresetPalette_BlackAndWhite(void) +{ + gCanvasPalette[0] = RGB2(0, 0, 0); + gCanvasPalette[1] = RGB2(0, 0, 0); + gCanvasPalette[2] = RGB2(31, 31, 31); +} + +static void SetPresetPalette_GrayscaleSmall(void) +{ + u8 i; + + gCanvasPalette[0] = RGB2(0, 0, 0); + gCanvasPalette[1] = RGB2(0, 0, 0); + for (i = 0; i < 14; i++) + gCanvasPalette[i + 2] = RGB2(2 * (i + 2), 2 * (i + 2), 2 * (i + 2)); +} + +static void SetPresetPalette_Grayscale(void) +{ + u8 i; + + gCanvasPalette[0] = RGB2(0, 0, 0); + for (i = 0; i < 32; i++) + gCanvasPalette[i + 1] = RGB2(i, i, i); +} + +static void QuantizePalette_Standard(bool8 useLimitedPalette) +{ + u8 i, j; + u16 maxIndex; + + maxIndex = 0xDF; + if (!useLimitedPalette) + maxIndex = 0xFF; + + for (i = 0; i < maxIndex; i++) + gCanvasPalette[i] = RGB_BLACK; + + gCanvasPalette[maxIndex] = RGB2(15, 15, 15); + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (*pixel & 0x8000) + { + *pixel = gCanvasPaletteStart; + } + else + { + u16 quantizedColor = QuantizePixel_Standard(pixel); + u8 curIndex = 1; + if (curIndex < maxIndex) + { + if (gCanvasPalette[curIndex] == RGB_BLACK) + { + // The quantized color does not match any existing color in the + // palette, so we add it to the palette. + // This if block seems pointless because the below while loop handles + // this same logic. + gCanvasPalette[curIndex] = quantizedColor; + *pixel = gCanvasPaletteStart + curIndex; + } + else + { + while (curIndex < maxIndex) + { + if (gCanvasPalette[curIndex] == RGB_BLACK) + { + // The quantized color does not match any existing color in the + // palette, so we add it to the palette. + gCanvasPalette[curIndex] = quantizedColor; + *pixel = gCanvasPaletteStart + curIndex; + break; + } + + if (gCanvasPalette[curIndex] == quantizedColor) + { + // The quantized color matches this existing color in the + // palette, so we use this existing color for the pixel. + *pixel = gCanvasPaletteStart + curIndex; + break; + } + + curIndex++; + } + } + } + + if (curIndex == maxIndex) + { + // The entire palette's colors are already in use, which means + // the base image has too many colors to handle. This error is handled + // by marking such pixels as gray color. + curIndex = maxIndex; + *pixel = curIndex; + } + } + } + } +} + +static void QuantizePalette_BlackAndWhite(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (*pixel & 0x8000) + { + *pixel = gCanvasPaletteStart; + } + else + { + if (QuantizePixel_BlackAndWhite(pixel) == RGB_BLACK) + { + // Black is the first color in the quantized palette. + *pixel = gCanvasPaletteStart + 1; + } + else + { + // White is the second color in the quantized palette. + *pixel = gCanvasPaletteStart + 2; + } + } + } + } +} + +static void QuantizePalette_GrayscaleSmall(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (*pixel & 0x8000) + *pixel = gCanvasPaletteStart; + else + *pixel = QuantizePixel_GrayscaleSmall(pixel) + gCanvasPaletteStart; + } + } +} + +static void QuantizePalette_Grayscale(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (*pixel & 0x8000) + *pixel = gCanvasPaletteStart; + else + *pixel = QuantizePixel_Grayscale(pixel) + gCanvasPaletteStart; + } + } +} + +static void QuantizePalette_PrimaryColors(void) +{ + u8 i, j; + + for (j = 0; j < gCanvasRowEnd; j++) + { + u16 *pixelRow = &(*gCanvasPixels)[0][(gCanvasRowStart + j) * gCanvasWidth]; + u16 *pixel = &pixelRow[gCanvasColumnStart]; + for (i = 0; i < gCanvasColumnEnd; i++, pixel++) + { + if (*pixel & 0x8000) + *pixel = gCanvasPaletteStart; + else + *pixel = QuantizePixel_PrimaryColors(pixel) + gCanvasPaletteStart; + } + } +} + +// Quantizes the pixel's color channels to nearest multiple of 4, and clamps to [6, 30]. +static u16 QuantizePixel_Standard(u16 *pixel) +{ + u16 red = *pixel & 0x1F; + u16 green = (*pixel >> 5) & 0x1F; + u16 blue = (*pixel >> 10) & 0x1F; + + // Quantize color channels to muliples of 4, rounding up. + if (red & 3) + red = (red & 0x1C) + 4; + if (green & 3) + green = (green & 0x1C) + 4; + if (blue & 3) + blue = (blue & 0x1C) + 4; + + // Clamp channels to [6, 30]. + if (red < 6) + red = 6; + if (red > 30) + red = 30; + if (green < 6) + green = 6; + if (green > 30) + green = 30; + if (blue < 6) + blue = 6; + if (blue > 30) + blue = 30; + + return RGB2(red, green, blue); +} + +static u16 QuantizePixel_PrimaryColors(u16* color) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + + if (red < 12 && green < 11 && blue < 11) + return 1; + + if (red > 19 && green > 19 && blue > 19) + return 2; + + if (red > 19) + { + if (green > 19) + { + if (blue > 14) + return 2; + else + return 7; + } + else if (blue > 19) + { + if (green > 14) + return 2; + else + return 8; + } + } + + if (green > 19 && blue > 19) + { + if (red > 14) + return 2; + else + return 9; + } + + if (red > 19) + { + if (green > 11) + { + if (blue > 11) + { + if (green < blue) + return 8; + else + return 7; + } + else + { + return 10; + } + } + else if (blue > 11) + { + return 13; + } + else + { + return 4; + } + } + + if (green > 19) + { + if (red > 11) + { + if (blue > 11) + { + if (red < blue) + return 9; + else + return 7; + } + else + { + return 11; + } + } + else + { + if (blue > 11) + return 14; + else + return 5; + } + } + + if (blue > 19) + { + if (red > 11) + { + if (green > 11) + { + if (red < green) + return 9; + else + return 8; + } + } + else if (green > 11) + { + return 12; + } + + if (blue > 11) + return 15; + else + return 6; + } + + return 3; +} + +static u16 QuantizePixel_GrayscaleSmall(u16 *color) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + u16 average = ((red + green + blue) / 3) & 0x1E; + if (average == 0) + return 1; + else + return average / 2; +} + +static u16 QuantizePixel_Grayscale(u16 *color) +{ + u16 red = *color & 0x1F; + u16 green = (*color >> 5) & 0x1F; + u16 blue = (*color >> 10) & 0x1F; + u16 average = (red + green + blue) / 3; + return average + 1; +} -- cgit v1.2.3