mirror of
https://github.com/Cesarus85/ringfall-mjolnir-vr.git
synced 2026-10-17 17:00:35 +02:00
203 lines
5.6 KiB
C
203 lines
5.6 KiB
C
/*
|
|
BITMAPS_QUANTITIZE.C
|
|
|
|
symbols in this file:
|
|
0006D5D0 0020:
|
|
_bitmap_quantitize_read_row (0000)
|
|
0006D5F0 01d0:
|
|
_row_dither (0000)
|
|
0006D7C0 0250:
|
|
_bitmap_quantitize (0000)
|
|
00255338 0054:
|
|
??_C@_0FE@EDPMNCJK@bits_per_channel?$FLchannel_index?$FN?$DO@ (0000)
|
|
0025538C 002c:
|
|
??_C@_0CM@EPJOEJBJ@c?3?2halo?2SOURCE?2bitmaps?2bitmaps_q@ (0000)
|
|
002DCABC 0018:
|
|
_bits_per_channel_r5g6b5 (0000)
|
|
_bits_per_channel_a1r5g5b5 (0008)
|
|
_bits_per_channel_a4r4g4b4 (0010)
|
|
0031C314 0008:
|
|
_bits_per_channel_reversed (0000)
|
|
*/
|
|
|
|
/* ---------- headers */
|
|
|
|
#include "cseries.h"
|
|
|
|
#include "bitmaps/bitmap_group.h"
|
|
#include "bitmaps/bitmaps.h"
|
|
#include "bitmaps/bitmaps_quantitize_internal.h"
|
|
|
|
/* ---------- constants */
|
|
|
|
enum
|
|
{
|
|
CHANNEL_COUNT = 4,
|
|
CHANNEL_BITS = 8,
|
|
_bitmap_type_2d = 0,
|
|
};
|
|
|
|
/* ---------- macros */
|
|
|
|
/* ---------- structures */
|
|
|
|
/* ---------- prototypes */
|
|
|
|
static void bitmap_quantitize_read_row(
|
|
short *destination,
|
|
byte const *source,
|
|
short pixel_count);
|
|
static void row_dither(
|
|
short const *bits_per_channel,
|
|
short const *minimum_error,
|
|
short pixel_count,
|
|
short *source,
|
|
short *next_source,
|
|
byte *destination);
|
|
|
|
/* ---------- globals */
|
|
|
|
short bits_per_channel_r5g6b5[CHANNEL_COUNT] = { 0, 5, 6, 5 };
|
|
short bits_per_channel_a1r5g5b5[CHANNEL_COUNT] = { 8, 5, 5, 5 };
|
|
short bits_per_channel_a4r4g4b4[CHANNEL_COUNT] = { 4, 4, 4, 4 };
|
|
static short bits_per_channel_reversed[CHANNEL_COUNT] = { 0 };
|
|
|
|
/* ---------- public code */
|
|
|
|
void bitmap_quantitize(
|
|
struct bitmap_data *bitmap,
|
|
short const *bits_per_channel)
|
|
{
|
|
short minimum_error[CHANNEL_COUNT];
|
|
short *source;
|
|
short *next_source;
|
|
short channel_index;
|
|
short y;
|
|
|
|
match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 48, bitmap_verify(bitmap, TRUE));
|
|
|
|
if (bits_per_channel && bitmap->type == _bitmap_type_2d)
|
|
{
|
|
source = match_malloc("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 52, bitmap->width * CHANNEL_COUNT * sizeof(short));
|
|
next_source = match_malloc("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 53, bitmap->width * CHANNEL_COUNT * sizeof(short));
|
|
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
{
|
|
match_assert("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 63, bits_per_channel[channel_index]>=0 && bits_per_channel[channel_index]<=CHANNEL_BITS);
|
|
}
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
bits_per_channel_reversed[CHANNEL_COUNT - 1 - channel_index] = bits_per_channel[channel_index];
|
|
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
minimum_error[channel_index] = (short)((1 << (CHANNEL_BITS - bits_per_channel_reversed[channel_index])) * 0.25f);
|
|
|
|
/* Original behavior: if exactly one allocation fails, the successful
|
|
* allocation is leaked. A corrected implementation would free either
|
|
* non-NULL buffer before leaving this block. */
|
|
if (source && next_source)
|
|
{
|
|
bitmap_quantitize_read_row(source, bitmap->base_address, bitmap->width);
|
|
|
|
for (y = 0; y < bitmap->height - 1; y++)
|
|
{
|
|
bitmap_quantitize_read_row(
|
|
next_source,
|
|
bitmap_2d_address(bitmap, 0, (short)(y + 1), 0),
|
|
bitmap->width);
|
|
row_dither(
|
|
bits_per_channel_reversed,
|
|
minimum_error,
|
|
bitmap->width,
|
|
source,
|
|
next_source,
|
|
bitmap_2d_address(bitmap, 0, y, 0));
|
|
{
|
|
short *swap = source;
|
|
source = next_source;
|
|
next_source = swap;
|
|
}
|
|
}
|
|
|
|
row_dither(
|
|
bits_per_channel_reversed,
|
|
minimum_error,
|
|
bitmap->width,
|
|
source,
|
|
NULL,
|
|
bitmap_2d_address(bitmap, 0, (short)(bitmap->height - 1), 0));
|
|
match_free("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 115, source);
|
|
match_free("c:\\halo\\SOURCE\\bitmaps\\bitmaps_quantitize.c", 116, next_source);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
/* ---------- private code */
|
|
|
|
static void bitmap_quantitize_read_row(
|
|
short *destination,
|
|
byte const *source,
|
|
short pixel_count)
|
|
{
|
|
long channel_count = pixel_count * CHANNEL_COUNT;
|
|
|
|
while (channel_count-- > 0)
|
|
*destination++ = *source++;
|
|
return;
|
|
}
|
|
|
|
static void row_dither(
|
|
short const *bits_per_channel,
|
|
short const *minimum_error,
|
|
short pixel_count,
|
|
short *source,
|
|
short *next_source,
|
|
byte *destination)
|
|
{
|
|
short pixel_index;
|
|
|
|
for (pixel_index = 0; pixel_index < pixel_count; pixel_index++)
|
|
{
|
|
byte original[CHANNEL_COUNT];
|
|
byte quantized[CHANNEL_COUNT];
|
|
short channel_index;
|
|
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
{
|
|
original[channel_index] = PIN(source[channel_index], 0, 255);
|
|
}
|
|
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
{
|
|
destination[channel_index] = quantized[channel_index] = bits_per_channel[channel_index] ?
|
|
((original[channel_index] >> (CHANNEL_BITS - bits_per_channel[channel_index])) * 255) /
|
|
((1 << bits_per_channel[channel_index]) - 1) :
|
|
0;
|
|
}
|
|
|
|
for (channel_index = 0; channel_index < CHANNEL_COUNT; channel_index++)
|
|
{
|
|
short error = original[channel_index] - quantized[channel_index];
|
|
|
|
if (pixel_index < pixel_count - 1 && source[CHANNEL_COUNT + channel_index] > minimum_error[channel_index])
|
|
source[CHANNEL_COUNT + channel_index] += (error * 7) / 16;
|
|
|
|
if (next_source)
|
|
{
|
|
if (pixel_index && next_source[-CHANNEL_COUNT + channel_index] > minimum_error[channel_index])
|
|
next_source[-CHANNEL_COUNT + channel_index] += (error * 3) / 16;
|
|
if (next_source[channel_index] > minimum_error[channel_index])
|
|
next_source[channel_index] += (error * 5) / 16;
|
|
if (pixel_index < pixel_count - 1 && next_source[CHANNEL_COUNT + channel_index] > minimum_error[channel_index])
|
|
next_source[CHANNEL_COUNT + channel_index] += error / 16;
|
|
}
|
|
}
|
|
|
|
source += CHANNEL_COUNT;
|
|
destination += CHANNEL_COUNT;
|
|
if (next_source)
|
|
next_source += CHANNEL_COUNT;
|
|
}
|
|
return;
|
|
}
|