mirror of https://github.com/axmolengine/axmol.git
295 lines
8.5 KiB
C++
295 lines
8.5 KiB
C++
// ----------------------------------------------------------------------------
|
|
// This confidential and proprietary software may be used only as authorised
|
|
// by a licensing agreement from Arm Limited.
|
|
// (C) COPYRIGHT 2011-2019 Arm Limited, ALL RIGHTS RESERVED
|
|
// The entire notice above must be reproduced on all authorised copies and
|
|
// copies may only be made to the extent permitted by a licensing agreement
|
|
// from Arm Limited.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/**
|
|
* @brief Functions to decompress a symbolic block.
|
|
*/
|
|
|
|
#include "astc_codec_internals.h"
|
|
#include "softfloat.h"
|
|
|
|
#include <stdio.h>
|
|
|
|
int compute_value_of_texel_int(int texel_to_get, const decimation_table * it, const int *weights)
|
|
{
|
|
int i;
|
|
int summed_value = 8;
|
|
int weights_to_evaluate = it->texel_num_weights[texel_to_get];
|
|
for (i = 0; i < weights_to_evaluate; i++)
|
|
{
|
|
summed_value += weights[it->texel_weights[texel_to_get][i]] * it->texel_weights_int[texel_to_get][i];
|
|
}
|
|
return summed_value >> 4;
|
|
}
|
|
|
|
ushort4 lerp_color_int(astc_decode_mode decode_mode, ushort4 color0, ushort4 color1, int weight, int plane2_weight, int plane2_color_component // -1 in 1-plane mode
|
|
)
|
|
{
|
|
int4 ecolor0 = int4(color0.x, color0.y, color0.z, color0.w);
|
|
int4 ecolor1 = int4(color1.x, color1.y, color1.z, color1.w);
|
|
|
|
int4 eweight1 = int4(weight, weight, weight, weight);
|
|
switch (plane2_color_component)
|
|
{
|
|
case 0:
|
|
eweight1.x = plane2_weight;
|
|
break;
|
|
case 1:
|
|
eweight1.y = plane2_weight;
|
|
break;
|
|
case 2:
|
|
eweight1.z = plane2_weight;
|
|
break;
|
|
case 3:
|
|
eweight1.w = plane2_weight;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
int4 eweight0 = int4(64, 64, 64, 64) - eweight1;
|
|
|
|
if (decode_mode == DECODE_LDR_SRGB)
|
|
{
|
|
ecolor0 = ecolor0 >> 8;
|
|
ecolor1 = ecolor1 >> 8;
|
|
}
|
|
int4 color = (ecolor0 * eweight0) + (ecolor1 * eweight1) + int4(32, 32, 32, 32);
|
|
color = color >> 6;
|
|
if (decode_mode == DECODE_LDR_SRGB)
|
|
color = color | (color << 8);
|
|
|
|
ushort4 rcolor = ushort4(color.x, color.y, color.z, color.w);
|
|
return rcolor;
|
|
}
|
|
|
|
void decompress_symbolic_block(astc_decode_mode decode_mode,
|
|
int xdim, int ydim, int zdim, // dimensions of block
|
|
int xpos, int ypos, int zpos, // position of block
|
|
const symbolic_compressed_block * scb, imageblock * blk)
|
|
{
|
|
blk->xpos = xpos;
|
|
blk->ypos = ypos;
|
|
blk->zpos = zpos;
|
|
|
|
int i;
|
|
|
|
// if we detected an error-block, blow up immediately.
|
|
if (scb->error_block)
|
|
{
|
|
if (decode_mode == DECODE_LDR_SRGB)
|
|
{
|
|
for (i = 0; i < xdim * ydim * zdim; i++)
|
|
{
|
|
blk->orig_data[4 * i] = 1.0f;
|
|
blk->orig_data[4 * i + 1] = 0.0f;
|
|
blk->orig_data[4 * i + 2] = 1.0f;
|
|
blk->orig_data[4 * i + 3] = 1.0f;
|
|
blk->rgb_lns[i] = 0;
|
|
blk->alpha_lns[i] = 0;
|
|
blk->nan_texel[i] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (i = 0; i < xdim * ydim * zdim; i++)
|
|
{
|
|
blk->orig_data[4 * i] = 0.0f;
|
|
blk->orig_data[4 * i + 1] = 0.0f;
|
|
blk->orig_data[4 * i + 2] = 0.0f;
|
|
blk->orig_data[4 * i + 3] = 0.0f;
|
|
blk->rgb_lns[i] = 0;
|
|
blk->alpha_lns[i] = 0;
|
|
blk->nan_texel[i] = 1;
|
|
}
|
|
}
|
|
|
|
imageblock_initialize_work_from_orig(blk, xdim * ydim * zdim);
|
|
update_imageblock_flags(blk, xdim, ydim, zdim);
|
|
return;
|
|
}
|
|
|
|
if (scb->block_mode < 0)
|
|
{
|
|
float red = 0, green = 0, blue = 0, alpha = 0;
|
|
int use_lns = 0;
|
|
int use_nan = 0;
|
|
|
|
if (scb->block_mode == -2)
|
|
{
|
|
// For sRGB decoding, we should return only the top 8 bits.
|
|
int mask = (decode_mode == DECODE_LDR_SRGB) ? 0xFF00 : 0xFFFF;
|
|
|
|
red = sf16_to_float(unorm16_to_sf16(scb->constant_color[0] & mask));
|
|
green = sf16_to_float(unorm16_to_sf16(scb->constant_color[1] & mask));
|
|
blue = sf16_to_float(unorm16_to_sf16(scb->constant_color[2] & mask));
|
|
alpha = sf16_to_float(unorm16_to_sf16(scb->constant_color[3] & mask));
|
|
use_lns = 0;
|
|
use_nan = 0;
|
|
}
|
|
else
|
|
{
|
|
switch (decode_mode)
|
|
{
|
|
case DECODE_LDR_SRGB:
|
|
red = 1.0f;
|
|
green = 0.0f;
|
|
blue = 1.0f;
|
|
alpha = 1.0f;
|
|
use_lns = 0;
|
|
use_nan = 0;
|
|
break;
|
|
case DECODE_LDR:
|
|
red = 0.0f;
|
|
green = 0.0f;
|
|
blue = 0.0f;
|
|
alpha = 0.0f;
|
|
use_lns = 0;
|
|
use_nan = 1;
|
|
break;
|
|
case DECODE_HDR:
|
|
// constant-color block; unpack from FP16 to FP32.
|
|
red = sf16_to_float(scb->constant_color[0]);
|
|
green = sf16_to_float(scb->constant_color[1]);
|
|
blue = sf16_to_float(scb->constant_color[2]);
|
|
alpha = sf16_to_float(scb->constant_color[3]);
|
|
use_lns = 1;
|
|
use_nan = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < xdim * ydim * zdim; i++)
|
|
{
|
|
blk->orig_data[4 * i] = red;
|
|
blk->orig_data[4 * i + 1] = green;
|
|
blk->orig_data[4 * i + 2] = blue;
|
|
blk->orig_data[4 * i + 3] = alpha;
|
|
blk->rgb_lns[i] = use_lns;
|
|
blk->alpha_lns[i] = use_lns;
|
|
blk->nan_texel[i] = use_nan;
|
|
}
|
|
|
|
imageblock_initialize_work_from_orig(blk, xdim * ydim * zdim);
|
|
update_imageblock_flags(blk, xdim, ydim, zdim);
|
|
return;
|
|
}
|
|
|
|
// get the appropriate partition-table entry
|
|
int partition_count = scb->partition_count;
|
|
const partition_info *pt = get_partition_table(xdim, ydim, zdim, partition_count);
|
|
pt += scb->partition_index;
|
|
|
|
// get the appropriate block descriptor
|
|
const block_size_descriptor *bsd = get_block_size_descriptor(xdim, ydim, zdim);
|
|
const decimation_table *const *ixtab2 = bsd->decimation_tables;
|
|
|
|
const decimation_table *it = ixtab2[bsd->block_modes[scb->block_mode].decimation_mode];
|
|
|
|
int is_dual_plane = bsd->block_modes[scb->block_mode].is_dual_plane;
|
|
|
|
int weight_quantization_level = bsd->block_modes[scb->block_mode].quantization_mode;
|
|
|
|
// decode the color endpoints
|
|
ushort4 color_endpoint0[4];
|
|
ushort4 color_endpoint1[4];
|
|
int rgb_hdr_endpoint[4];
|
|
int alpha_hdr_endpoint[4];
|
|
int nan_endpoint[4];
|
|
|
|
for (i = 0; i < partition_count; i++)
|
|
unpack_color_endpoints(decode_mode,
|
|
scb->color_formats[i],
|
|
scb->color_quantization_level, scb->color_values[i], &(rgb_hdr_endpoint[i]), &(alpha_hdr_endpoint[i]), &(nan_endpoint[i]), &(color_endpoint0[i]), &(color_endpoint1[i]));
|
|
|
|
// first unquantize the weights
|
|
int uq_plane1_weights[MAX_WEIGHTS_PER_BLOCK];
|
|
int uq_plane2_weights[MAX_WEIGHTS_PER_BLOCK];
|
|
int weight_count = it->num_weights;
|
|
|
|
const quantization_and_transfer_table *qat = &(quant_and_xfer_tables[weight_quantization_level]);
|
|
|
|
for (i = 0; i < weight_count; i++)
|
|
{
|
|
uq_plane1_weights[i] = qat->unquantized_value[scb->plane1_weights[i]];
|
|
}
|
|
|
|
if (is_dual_plane)
|
|
{
|
|
for (i = 0; i < weight_count; i++)
|
|
uq_plane2_weights[i] = qat->unquantized_value[scb->plane2_weights[i]];
|
|
}
|
|
|
|
// then undecimate them.
|
|
int weights[MAX_TEXELS_PER_BLOCK];
|
|
int plane2_weights[MAX_TEXELS_PER_BLOCK];
|
|
|
|
int texels_per_block = xdim * ydim * zdim;
|
|
for (i = 0; i < texels_per_block; i++)
|
|
weights[i] = compute_value_of_texel_int(i, it, uq_plane1_weights);
|
|
|
|
if (is_dual_plane)
|
|
for (i = 0; i < texels_per_block; i++)
|
|
plane2_weights[i] = compute_value_of_texel_int(i, it, uq_plane2_weights);
|
|
|
|
int plane2_color_component = scb->plane2_color_component;
|
|
|
|
// now that we have endpoint colors and weights, we can unpack actual colors for
|
|
// each texel.
|
|
for (i = 0; i < texels_per_block; i++)
|
|
{
|
|
int partition = pt->partition_of_texel[i];
|
|
|
|
ushort4 color = lerp_color_int(decode_mode,
|
|
color_endpoint0[partition],
|
|
color_endpoint1[partition],
|
|
weights[i],
|
|
plane2_weights[i],
|
|
is_dual_plane ? plane2_color_component : -1);
|
|
|
|
blk->rgb_lns[i] = rgb_hdr_endpoint[partition];
|
|
blk->alpha_lns[i] = alpha_hdr_endpoint[partition];
|
|
blk->nan_texel[i] = nan_endpoint[partition];
|
|
|
|
blk->work_data[4 * i] = color.x;
|
|
blk->work_data[4 * i + 1] = color.y;
|
|
blk->work_data[4 * i + 2] = color.z;
|
|
blk->work_data[4 * i + 3] = color.w;
|
|
}
|
|
|
|
imageblock_initialize_orig_from_work(blk, xdim * ydim * zdim);
|
|
|
|
update_imageblock_flags(blk, xdim, ydim, zdim);
|
|
}
|
|
|
|
float compute_imageblock_difference(int xdim, int ydim, int zdim, const imageblock * p1, const imageblock * p2, const error_weight_block * ewb)
|
|
{
|
|
int i;
|
|
int texels_per_block = xdim * ydim * zdim;
|
|
float summa = 0.0f;
|
|
const float *f1 = p1->work_data;
|
|
const float *f2 = p2->work_data;
|
|
|
|
for (i = 0; i < texels_per_block; i++)
|
|
{
|
|
float rdiff = fabsf(f1[4 * i] - f2[4 * i]);
|
|
float gdiff = fabs(f1[4 * i + 1] - f2[4 * i + 1]);
|
|
float bdiff = fabs(f1[4 * i + 2] - f2[4 * i + 2]);
|
|
float adiff = fabs(f1[4 * i + 3] - f2[4 * i + 3]);
|
|
rdiff = MIN(rdiff, 1e15f);
|
|
gdiff = MIN(gdiff, 1e15f);
|
|
bdiff = MIN(bdiff, 1e15f);
|
|
adiff = MIN(adiff, 1e15f);
|
|
|
|
summa += rdiff * rdiff * ewb->error_weights[i].x + gdiff * gdiff * ewb->error_weights[i].y + bdiff * bdiff * ewb->error_weights[i].z + adiff * adiff * ewb->error_weights[i].w;
|
|
}
|
|
|
|
return summa;
|
|
}
|