osx fixes. Fix issue 211.
This commit is contained in:
@ -1,8 +1,6 @@
|
||||
PROJECT(nvtt)
|
||||
|
||||
ADD_SUBDIRECTORY(squish)
|
||||
ADD_SUBDIRECTORY(bc6h)
|
||||
ADD_SUBDIRECTORY(bc7)
|
||||
|
||||
SET(NVTT_SRCS
|
||||
nvtt.h nvtt.cpp
|
||||
@ -13,6 +11,7 @@ SET(NVTT_SRCS
|
||||
CompressorDX9.h CompressorDX9.cpp
|
||||
CompressorDX10.h CompressorDX10.cpp
|
||||
CompressorDX11.h CompressorDX11.cpp
|
||||
CompressorDXT1.h CompressorDXT1.cpp
|
||||
CompressorRGB.h CompressorRGB.cpp
|
||||
Context.h Context.cpp
|
||||
QuickCompressDXT.h QuickCompressDXT.cpp
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
#include <string.h> // memset
|
||||
#include <float.h> // FLT_MAX
|
||||
|
||||
|
||||
using namespace nv;
|
||||
@ -80,14 +81,14 @@ static Color32 bitexpand_color16_to_color32(Color16 c16) {
|
||||
return c32;
|
||||
}
|
||||
|
||||
static Color32 bitexpand_color16_to_color32(int r, int g, int b) {
|
||||
/*static Color32 bitexpand_color16_to_color32(int r, int g, int b) {
|
||||
Color32 c32;
|
||||
c32.b = (b << 3) | (b >> 2);
|
||||
c32.g = (g << 2) | (g >> 4);
|
||||
c32.r = (r << 3) | (r >> 2);
|
||||
c32.a = 0xFF;
|
||||
return c32;
|
||||
}
|
||||
}*/
|
||||
|
||||
static Color16 truncate_color32_to_color16(Color32 c32) {
|
||||
Color16 c16;
|
||||
@ -97,14 +98,14 @@ static Color16 truncate_color32_to_color16(Color32 c32) {
|
||||
return c16;
|
||||
}
|
||||
|
||||
inline Vector3 r5g6b5_to_vector3(int r, int g, int b)
|
||||
/*inline Vector3 r5g6b5_to_vector3(int r, int g, int b)
|
||||
{
|
||||
Vector3 c;
|
||||
c.x = float((r << 3) | (r >> 2));
|
||||
c.y = float((g << 2) | (g >> 4));
|
||||
c.z = float((b << 3) | (b >> 2));
|
||||
return c;
|
||||
}
|
||||
}*/
|
||||
|
||||
inline Vector3 color_to_vector3(Color32 c)
|
||||
{
|
||||
@ -711,3 +712,92 @@ float nv::compress_dxt1(const Vector3 input_colors[16], const float input_weight
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
// Once we have an index assignment we have colors grouped in 1-4 clusters.
|
||||
// If 1 clusters -> Use optimal compressor.
|
||||
// If 2 clusters -> Try: (0, 1), (1, 2), (0, 2), (0, 3) - [0, 1]
|
||||
// If 3 clusters -> Try: (0, 1, 2), (0, 1, 3), (0, 2, 3) - [0, 1, 2]
|
||||
// If 4 clusters -> Try: (0, 1, 2, 3)
|
||||
|
||||
// @@ How do we do the initial index/cluster assignment? Use standard cluster fit.
|
||||
|
||||
|
||||
// Least squares fitting of color end points for the given indices. @@ Take weights into account.
|
||||
static bool optimize_end_points4(uint indices, const Vector3 * colors, const Vector3 * weights, int count, Vector3 * a, Vector3 * b)
|
||||
{
|
||||
float alpha2_sum = 0.0f;
|
||||
float beta2_sum = 0.0f;
|
||||
float alphabeta_sum = 0.0f;
|
||||
Vector3 alphax_sum(0.0f);
|
||||
Vector3 betax_sum(0.0f);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
const uint bits = indices >> (2 * i);
|
||||
|
||||
float beta = float(bits & 1);
|
||||
if (bits & 2) beta = (1 + beta) / 3.0f;
|
||||
float alpha = 1.0f - beta;
|
||||
|
||||
alpha2_sum += alpha * alpha;
|
||||
beta2_sum += beta * beta;
|
||||
alphabeta_sum += alpha * beta;
|
||||
alphax_sum += alpha * colors[i];
|
||||
betax_sum += beta * colors[i];
|
||||
}
|
||||
|
||||
float denom = alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum;
|
||||
if (equal(denom, 0.0f)) return false;
|
||||
|
||||
float factor = 1.0f / denom;
|
||||
|
||||
*a = saturate((alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor);
|
||||
*b = saturate((betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Least squares fitting of color end points for the given indices. @@ This does not support black/transparent index. @@ Take weights into account.
|
||||
static bool optimize_end_points3(uint indices, const Vector3 * colors, const Vector3 * weights, int count, Vector3 * a, Vector3 * b)
|
||||
{
|
||||
float alpha2_sum = 0.0f;
|
||||
float beta2_sum = 0.0f;
|
||||
float alphabeta_sum = 0.0f;
|
||||
Vector3 alphax_sum(0.0f);
|
||||
Vector3 betax_sum(0.0f);
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
const uint bits = indices >> (2 * i);
|
||||
|
||||
float beta = float(bits & 1);
|
||||
if (bits & 2) beta = 0.5f;
|
||||
float alpha = 1.0f - beta;
|
||||
|
||||
alpha2_sum += alpha * alpha;
|
||||
beta2_sum += beta * beta;
|
||||
alphabeta_sum += alpha * beta;
|
||||
alphax_sum += alpha * colors[i];
|
||||
betax_sum += beta * colors[i];
|
||||
}
|
||||
|
||||
float denom = alpha2_sum * beta2_sum - alphabeta_sum * alphabeta_sum;
|
||||
if (equal(denom, 0.0f)) return false;
|
||||
|
||||
float factor = 1.0f / denom;
|
||||
|
||||
*a = saturate((alphax_sum * beta2_sum - betax_sum * alphabeta_sum) * factor);
|
||||
*b = saturate((betax_sum * alpha2_sum - alphax_sum * alphabeta_sum) * factor);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// @@ After optimization we need to round end points. Round in all possible directions, and pick best.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -8,23 +8,6 @@ namespace nv {
|
||||
|
||||
// All these functions return MSE.
|
||||
|
||||
// Optimal compressors:
|
||||
/*float compress_dxt1_single_color_optimal(const Color32 & rgb, BlockDXT1 * output);
|
||||
float compress_dxt1_single_color_optimal(const ColorBlock & input, BlockDXT1 * output);
|
||||
float compress_dxt1_optimal(const ColorBlock & input, BlockDXT1 * output);
|
||||
|
||||
|
||||
|
||||
// Brute force with restricted search space:
|
||||
float compress_dxt1_bounding_box_exhaustive(const ColorBlock & input, BlockDXT1 * output);
|
||||
float compress_dxt1_best_fit_line_exhaustive(const ColorBlock & input, BlockDXT1 * output);
|
||||
|
||||
|
||||
// Fast least squres fitting compressors:
|
||||
float compress_dxt1_least_squares_fit(const ColorBlock & input, BlockDXT1 * output);
|
||||
float compress_dxt1_least_squares_fit_iterative(const ColorBlock & input, BlockDXT1 * output);
|
||||
*/
|
||||
|
||||
float compress_dxt1_single_color_optimal(Color32 c, BlockDXT1 * output);
|
||||
float compress_dxt1_single_color_optimal(const Vector3 & color, BlockDXT1 * output);
|
||||
|
||||
@ -36,4 +19,4 @@ namespace nv {
|
||||
|
||||
float compress_dxt1(const Vector3 colors[16], const float weights[16], const Vector3 & color_weights, BlockDXT1 * output);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "nvcore/Utils.h" // swap
|
||||
|
||||
#include <string.h> // memset
|
||||
#include <float.h> // FLT_MAX
|
||||
|
||||
using namespace nv;
|
||||
using namespace QuickCompress;
|
||||
@ -285,7 +286,7 @@ inline static uint computeIndices4(const ColorSet & set, Vector3::Arg maxColor,
|
||||
}
|
||||
|
||||
swap(row0, row1);
|
||||
memset(row1, 0, sizeof(row1));
|
||||
memset(row1, 0, sizeof(Vector3) * (4+2));
|
||||
}
|
||||
|
||||
return indices;
|
||||
@ -866,108 +867,3 @@ void QuickCompress::outputBlock3(const ColorSet & set, const Vector3 & start, co
|
||||
//optimizeEndPoints3(set, block);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
inline Vector3 toVectorColor(int r, int g, int b) {
|
||||
Vector3 c;
|
||||
c.x = float((r << 3) | (r >> 2));
|
||||
c.y = float((g << 2) | (g >> 4));
|
||||
c.z = float((b << 3) | (b >> 2));
|
||||
return c;
|
||||
}
|
||||
|
||||
// Do an exhaustive search inside the bounding box.
|
||||
void compress_dxt1_bounding_box_exhaustive(const ColorBlock & input, BlockDXT1 * output)
|
||||
{
|
||||
int min_r = 255, min_g = 255, min_b = 255;
|
||||
int max_r = 0, max_g = 0, max_b = 0;
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
Color32 c = input.color(i);
|
||||
min_r = min(min_r, int(c.r));
|
||||
max_r = max(max_r, int(c.r));
|
||||
min_g = min(min_g, int(c.g));
|
||||
max_g = max(max_g, int(c.g));
|
||||
min_b = min(min_b, int(c.b));
|
||||
max_b = max(max_b, int(c.b));
|
||||
}
|
||||
|
||||
// Convert to 5:6:5
|
||||
min_r >>= 3; min_g >>= 2; min_b >>= 3;
|
||||
max_r >>= 3; max_g >>= 2; max_b >>= 3;
|
||||
|
||||
// Expand the box.
|
||||
int range_r = max_r - min_r;
|
||||
int range_g = max_g - min_g;
|
||||
int range_b = max_b - min_b;
|
||||
|
||||
min_r = max(0, min_r - (range_r + 1) / 1 - 1);
|
||||
min_g = max(0, min_g - (range_g + 1) / 1 - 1);
|
||||
min_b = max(0, min_b - (range_b + 1) / 1 - 1);
|
||||
|
||||
max_r = min(31, max_r + (range_r + 1) / 2 + 1);
|
||||
max_g = min(63, max_g + (range_g + 1) / 2 + 1);
|
||||
max_b = min(31, max_b + (range_b + 1) / 2 + 1);
|
||||
|
||||
int count = (max_r-min_r) + (max_g-min_g) + (max_b-min_b);
|
||||
|
||||
Vector3 colors[16];
|
||||
extractColorBlockRGB(input, colors);
|
||||
|
||||
|
||||
// @@ Use a single loop and remap index to box location?
|
||||
float bestError = FLT_MAX;
|
||||
Vector3 best0, best1;
|
||||
bool threeColorMode;
|
||||
|
||||
for(int r0 = min_r; r0 <= max_r; r0++)
|
||||
for(int r1 = max_r; r1 >= r0; r1--)
|
||||
for(int g0 = min_g; g0 <= max_g; g0++)
|
||||
for(int g1 = max_g; g1 >= g0; g1--)
|
||||
for(int b0 = min_b; b0 <= max_b; b0++)
|
||||
for(int b1 = max_b; b1 >= b0; b1--)
|
||||
{
|
||||
Vector3 c0 = toVectorColor(r0, g0, b0);
|
||||
Vector3 c1 = toVectorColor(r1, g1, b1);
|
||||
|
||||
// Compute palette and evaluate error for these endpoints.
|
||||
float error = evaluatePaletteError4(colors, c1, c0);
|
||||
|
||||
if (error < bestError) {
|
||||
bestError = error;
|
||||
best0 = c1; // c0 > c1
|
||||
best1 = c0;
|
||||
threeColorMode = false;
|
||||
}
|
||||
|
||||
#if 0
|
||||
error = evaluatePaletteError3(colors, /*maxColor=*/c1, /*minColor=*/c0);
|
||||
|
||||
if (error < bestError) {
|
||||
bestError = error;
|
||||
best0 = c0;
|
||||
best1 = c1;
|
||||
threeColorMode = true;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16 color0 = roundAndExpand(&best0);
|
||||
uint16 color1 = roundAndExpand(&best1);
|
||||
|
||||
if (threeColorMode) {
|
||||
nvCheck(color0 <= color1);
|
||||
output->col0 = Color16(color1);
|
||||
output->col1 = Color16(color0);
|
||||
output->indices = computeIndices3(colors, best0, best1);
|
||||
}
|
||||
else {
|
||||
nvCheck(color0 >= color1);
|
||||
output->col0 = Color16(color0);
|
||||
output->col1 = Color16(color1);
|
||||
output->indices = computeIndices4(colors, best0, best1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,22 +0,0 @@
|
||||
PROJECT(bc6h)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
SET(BC6H_SRCS
|
||||
bits.h
|
||||
shapes_two.h
|
||||
tile.h
|
||||
utils.cpp
|
||||
utils.h
|
||||
zoh.cpp
|
||||
zoh.h
|
||||
zohone.cpp
|
||||
zohtwo.cpp)
|
||||
|
||||
ADD_LIBRARY(bc6h STATIC ${BC6H_SRCS})
|
||||
|
||||
IF(NOT WIN32)
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET_TARGET_PROPERTIES(bc6h PROPERTIES COMPILE_FLAGS -fPIC)
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
ENDIF(NOT WIN32)
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef _ZOH_BITS_H
|
||||
#define _ZOH_BITS_H
|
||||
|
||||
// read/write a bitstream
|
||||
|
||||
#include "nvcore/Debug.h"
|
||||
|
||||
namespace ZOH {
|
||||
|
||||
class Bits
|
||||
{
|
||||
public:
|
||||
|
||||
Bits(char *data, int maxdatabits) { nvAssert (data && maxdatabits > 0); bptr = bend = 0; bits = data; maxbits = maxdatabits; readonly = 0;}
|
||||
Bits(const char *data, int availdatabits) { nvAssert (data && availdatabits > 0); bptr = 0; bend = availdatabits; cbits = data; maxbits = availdatabits; readonly = 1;}
|
||||
|
||||
void write(int value, int nbits) {
|
||||
nvAssert (nbits >= 0 && nbits < 32);
|
||||
nvAssert (sizeof(int)>= 4);
|
||||
for (int i=0; i<nbits; ++i)
|
||||
writeone(value>>i);
|
||||
}
|
||||
int read(int nbits) {
|
||||
nvAssert (nbits >= 0 && nbits < 32);
|
||||
nvAssert (sizeof(int)>= 4);
|
||||
int out = 0;
|
||||
for (int i=0; i<nbits; ++i)
|
||||
out |= readone() << i;
|
||||
return out;
|
||||
}
|
||||
int getptr() { return bptr; }
|
||||
void setptr(int ptr) { nvAssert (ptr >= 0 && ptr < maxbits); bptr = ptr; }
|
||||
int getsize() { return bend; }
|
||||
|
||||
private:
|
||||
int bptr; // next bit to read
|
||||
int bend; // last written bit + 1
|
||||
char *bits; // ptr to user bit stream
|
||||
const char *cbits; // ptr to const user bit stream
|
||||
int maxbits; // max size of user bit stream
|
||||
char readonly; // 1 if this is a read-only stream
|
||||
|
||||
int readone() {
|
||||
nvAssert (bptr < bend);
|
||||
if (bptr >= bend) return 0;
|
||||
int bit = (readonly ? cbits[bptr>>3] : bits[bptr>>3]) & (1 << (bptr & 7));
|
||||
++bptr;
|
||||
return bit != 0;
|
||||
}
|
||||
void writeone(int bit) {
|
||||
nvAssert (!readonly); // "Writing a read-only bit stream"
|
||||
nvAssert (bptr < maxbits);
|
||||
if (bptr >= maxbits) return;
|
||||
if (bit&1)
|
||||
bits[bptr>>3] |= 1 << (bptr & 7);
|
||||
else
|
||||
bits[bptr>>3] &= ~(1 << (bptr & 7));
|
||||
if (bptr++ >= bend) bend = bptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef _ZOH_SHAPES_TWO_H
|
||||
#define _ZOH_SHAPES_TWO_H
|
||||
|
||||
// shapes for two regions
|
||||
|
||||
#define NREGIONS 2
|
||||
#define NSHAPES 64
|
||||
#define SHAPEBITS 6
|
||||
|
||||
static const int shapes[NSHAPES*16] =
|
||||
{
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
|
||||
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
|
||||
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
|
||||
};
|
||||
|
||||
#define REGION(x,y,si) shapes[((si)&3)*4+((si)>>2)*64+(x)+(y)*16]
|
||||
|
||||
static const int shapeindex_to_compressed_indices[NSHAPES*2] =
|
||||
{
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
|
||||
0,15, 0, 2, 0, 8, 0, 2,
|
||||
0, 2, 0, 8, 0, 8, 0,15,
|
||||
0, 2, 0, 8, 0, 2, 0, 2,
|
||||
0, 8, 0, 8, 0, 2, 0, 2,
|
||||
|
||||
0,15, 0,15, 0, 6, 0, 8,
|
||||
0, 2, 0, 8, 0,15, 0,15,
|
||||
0, 2, 0, 8, 0, 2, 0, 2,
|
||||
0, 2, 0,15, 0,15, 0, 6,
|
||||
|
||||
0, 6, 0, 2, 0, 6, 0, 8,
|
||||
0,15, 0,15, 0, 2, 0, 2,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0, 2, 0, 2, 0,15
|
||||
|
||||
};
|
||||
#define SHAPEINDEX_TO_COMPRESSED_INDICES(si,region) shapeindex_to_compressed_indices[(si)*2+(region)]
|
||||
|
||||
#endif
|
@ -1,83 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef _ZOH_TILE_H
|
||||
#define _ZOH_TILE_H
|
||||
|
||||
#include "zoh_utils.h"
|
||||
#include "nvmath/Vector.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace ZOH {
|
||||
|
||||
//#define USE_IMPORTANCE_MAP 1 // define this if you want to increase importance of some pixels in tile
|
||||
class Tile
|
||||
{
|
||||
public:
|
||||
// NOTE: this returns the appropriately-clamped BIT PATTERN of the half as an INTEGRAL float value
|
||||
static float half2float(uint16 h)
|
||||
{
|
||||
return (float) Utils::ushort_to_format(h);
|
||||
}
|
||||
// NOTE: this is the inverse of the above operation
|
||||
static uint16 float2half(float f)
|
||||
{
|
||||
return Utils::format_to_ushort((int)f);
|
||||
}
|
||||
|
||||
// look for adjacent pixels that are identical. if there are enough of them, increase their importance
|
||||
void generate_importance_map()
|
||||
{
|
||||
// initialize
|
||||
for (int y=0; y<size_y; ++y)
|
||||
for (int x=0; x<size_x; ++x)
|
||||
{
|
||||
// my importance is increased if I am identical to any of my 4-neighbors
|
||||
importance_map[y][x] = match_4_neighbor(x,y) ? 5.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
bool is_equal(int x, int y, int xn, int yn)
|
||||
{
|
||||
if (xn < 0 || xn >= size_x || yn < 0 || yn >= size_y)
|
||||
return false;
|
||||
return( (data[y][x].x == data[yn][xn].x) &&
|
||||
(data[y][x].y == data[yn][xn].y) &&
|
||||
(data[y][x].z == data[yn][xn].z) );
|
||||
}
|
||||
|
||||
#ifdef USE_IMPORTANCE_MAP
|
||||
bool match_4_neighbor(int x, int y)
|
||||
{
|
||||
return is_equal(x,y,x-1,y) || is_equal(x,y,x+1,y) || is_equal(x,y,x,y-1) || is_equal(x,y,x,y+1);
|
||||
}
|
||||
#else
|
||||
bool match_4_neighbor(int x, int y)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Tile() {};
|
||||
~Tile(){};
|
||||
Tile(int xs, int ys) {size_x = xs; size_y = ys;}
|
||||
|
||||
static const int TILE_H = 4;
|
||||
static const int TILE_W = 4;
|
||||
static const int TILE_TOTAL = TILE_H * TILE_W;
|
||||
nv::Vector3 data[TILE_H][TILE_W];
|
||||
float importance_map[TILE_H][TILE_W];
|
||||
int size_x, size_y; // actual size of tile
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _ZOH_TILE_H
|
@ -1,197 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// the zoh compressor and decompressor
|
||||
|
||||
#include "tile.h"
|
||||
#include "zoh.h"
|
||||
|
||||
#include <string.h> // memcpy
|
||||
|
||||
using namespace ZOH;
|
||||
|
||||
|
||||
bool ZOH::isone(const char *block)
|
||||
{
|
||||
char code = block[0] & 0x1F;
|
||||
|
||||
return (code == 0x03 || code == 0x07 || code == 0x0b || code == 0x0f);
|
||||
}
|
||||
|
||||
void ZOH::compress(const Tile &t, char *block)
|
||||
{
|
||||
char oneblock[ZOH::BLOCKSIZE], twoblock[ZOH::BLOCKSIZE];
|
||||
|
||||
float mseone = ZOH::compressone(t, oneblock);
|
||||
float msetwo = ZOH::compresstwo(t, twoblock);
|
||||
|
||||
if (mseone <= msetwo)
|
||||
memcpy(block, oneblock, ZOH::BLOCKSIZE);
|
||||
else
|
||||
memcpy(block, twoblock, ZOH::BLOCKSIZE);
|
||||
}
|
||||
|
||||
void ZOH::decompress(const char *block, Tile &t)
|
||||
{
|
||||
if (ZOH::isone(block))
|
||||
ZOH::decompressone(block, t);
|
||||
else
|
||||
ZOH::decompresstwo(block, t);
|
||||
}
|
||||
|
||||
/*
|
||||
void ZOH::compress(string inf, string zohf)
|
||||
{
|
||||
Array2D<Rgba> pixels;
|
||||
int w, h;
|
||||
char block[ZOH::BLOCKSIZE];
|
||||
|
||||
Exr::readRgba(inf, pixels, w, h);
|
||||
FILE *zohfile = fopen(zohf.c_str(), "wb");
|
||||
if (zohfile == NULL) throw "Unable to open .zoh file for write";
|
||||
|
||||
// stuff for progress bar O.o
|
||||
int ntiles = ((h+Tile::TILE_H-1)/Tile::TILE_H)*((w+Tile::TILE_W-1)/Tile::TILE_W);
|
||||
int tilecnt = 0;
|
||||
int ndots = 25;
|
||||
int dotcnt = 0;
|
||||
printf("Progress [");
|
||||
for (int i=0; i<ndots;++i) printf(" ");
|
||||
printf("]\rProgress ["); fflush(stdout);
|
||||
|
||||
// convert to tiles and compress each tile
|
||||
for (int y=0; y<h; y+=Tile::TILE_H)
|
||||
{
|
||||
int ysize = min(Tile::TILE_H, h-y);
|
||||
for (int x=0; x<w; x+=Tile::TILE_W)
|
||||
{
|
||||
int xsize = min(Tile::TILE_W, w-x);
|
||||
Tile t(xsize, ysize);
|
||||
|
||||
t.insert(pixels, x, y);
|
||||
|
||||
ZOH::compress(t, block);
|
||||
if (fwrite(block, sizeof(char), ZOH::BLOCKSIZE, zohfile) != ZOH::BLOCKSIZE)
|
||||
throw "File error on write";
|
||||
|
||||
// progress bar
|
||||
++tilecnt;
|
||||
if (tilecnt > (ntiles * dotcnt)/ndots) { printf("."); fflush(stdout); ++dotcnt; }
|
||||
}
|
||||
}
|
||||
|
||||
printf("]\n"); // advance to next line finally
|
||||
|
||||
if (fclose(zohfile)) throw "Close failed on .zoh file";
|
||||
}
|
||||
|
||||
static int str2int(std::string s)
|
||||
{
|
||||
int thing;
|
||||
std::stringstream str (stringstream::in | stringstream::out);
|
||||
str << s;
|
||||
str >> thing;
|
||||
return thing;
|
||||
}
|
||||
|
||||
// zoh file name is ...-w-h.zoh, extract width and height
|
||||
static void extract(string zohf, int &w, int &h)
|
||||
{
|
||||
size_t n = zohf.rfind('.', zohf.length()-1);
|
||||
size_t n1 = zohf.rfind('-', n-1);
|
||||
size_t n2 = zohf.rfind('-', n1-1);
|
||||
string width = zohf.substr(n2+1, n1-n2-1);
|
||||
w = str2int(width);
|
||||
string height = zohf.substr(n1+1, n-n1-1);
|
||||
h = str2int(height);
|
||||
}
|
||||
|
||||
static int mode_to_prec[] = {
|
||||
10,7,11,10,
|
||||
10,7,11,11,
|
||||
10,7,11,12,
|
||||
10,7,9,16,
|
||||
10,7,8,-1,
|
||||
10,7,8,-1,
|
||||
10,7,8,-1,
|
||||
10,7,6,-1,
|
||||
};
|
||||
|
||||
static int shapeindexhist[32], modehist[32], prechistone[16], prechisttwo[16], oneregion, tworegions;
|
||||
|
||||
static void stats(char block[ZOH::BLOCKSIZE])
|
||||
{
|
||||
char mode = block[0] & 0x1F; if ((mode & 0x3) == 0) mode = 0; if ((mode & 0x3) == 1) mode = 1; modehist[mode]++;
|
||||
int prec = mode_to_prec[mode];
|
||||
nvAssert (prec != -1);
|
||||
if (!ZOH::isone(block))
|
||||
{
|
||||
tworegions++;
|
||||
prechisttwo[prec]++;
|
||||
int shapeindex = ((block[0] & 0xe0) >> 5) | ((block[1] & 0x3) << 3);
|
||||
shapeindexhist[shapeindex]++;
|
||||
}
|
||||
else
|
||||
{
|
||||
oneregion++;
|
||||
prechistone[prec]++;
|
||||
}
|
||||
}
|
||||
|
||||
static void printstats()
|
||||
{
|
||||
printf("\nPrecision histogram 10b to 16b one region: "); for (int i=10; i<=16; ++i) printf("%d,", prechistone[i]);
|
||||
printf("\nPrecision histogram 6b to 11b two regions: "); for (int i=6; i<=11; ++i) printf("%d,", prechisttwo[i]);
|
||||
printf("\nMode histogram: "); for (int i=0; i<32; ++i) printf("%d,", modehist[i]);
|
||||
printf("\nShape index histogram: "); for (int i=0; i<32; ++i) printf("%d,", shapeindexhist[i]);
|
||||
printf("\nOne region %5.2f%% Two regions %5.2f%%", 100.0*oneregion/float(oneregion+tworegions), 100.0*tworegions/float(oneregion+tworegions));
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void ZOH::decompress(string zohf, string outf)
|
||||
{
|
||||
Array2D<Rgba> pixels;
|
||||
int w, h;
|
||||
char block[ZOH::BLOCKSIZE];
|
||||
|
||||
extract(zohf, w, h);
|
||||
FILE *zohfile = fopen(zohf.c_str(), "rb");
|
||||
if (zohfile == NULL) throw "Unable to open .zoh file for read";
|
||||
pixels.resizeErase(h, w);
|
||||
|
||||
// convert to tiles and decompress each tile
|
||||
for (int y=0; y<h; y+=Tile::TILE_H)
|
||||
{
|
||||
int ysize = min(Tile::TILE_H, h-y);
|
||||
for (int x=0; x<w; x+=Tile::TILE_W)
|
||||
{
|
||||
int xsize = min(Tile::TILE_W, w-x);
|
||||
Tile t(xsize, ysize);
|
||||
|
||||
if (fread(block, sizeof(char), ZOH::BLOCKSIZE, zohfile) != ZOH::BLOCKSIZE)
|
||||
throw "File error on read";
|
||||
|
||||
stats(block); // collect statistics
|
||||
|
||||
ZOH::decompress(block, t);
|
||||
|
||||
t.extract(pixels, x, y);
|
||||
}
|
||||
}
|
||||
if (fclose(zohfile)) throw "Close failed on .zoh file";
|
||||
Exr::writeRgba(outf, pixels, w, h);
|
||||
|
||||
#ifndef EXTERNAL_RELEASE
|
||||
printstats(); // print statistics
|
||||
#endif
|
||||
}
|
||||
*/
|
@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#ifndef _ZOH_H
|
||||
#define _ZOH_H
|
||||
|
||||
#include "tile.h"
|
||||
|
||||
namespace ZOH {
|
||||
|
||||
// UNUSED ZOH MODES are 0x13, 0x17, 0x1b, 0x1f
|
||||
|
||||
static const int NREGIONS_TWO = 2;
|
||||
static const int NREGIONS_ONE = 1;
|
||||
static const int NCHANNELS = 3;
|
||||
|
||||
struct FltEndpts
|
||||
{
|
||||
nv::Vector3 A;
|
||||
nv::Vector3 B;
|
||||
};
|
||||
|
||||
struct IntEndpts
|
||||
{
|
||||
int A[NCHANNELS];
|
||||
int B[NCHANNELS];
|
||||
};
|
||||
|
||||
struct ComprEndpts
|
||||
{
|
||||
uint A[NCHANNELS];
|
||||
uint B[NCHANNELS];
|
||||
};
|
||||
|
||||
static const int BLOCKSIZE=16;
|
||||
static const int BITSIZE=128;
|
||||
|
||||
void compress(const Tile &t, char *block);
|
||||
void decompress(const char *block, Tile &t);
|
||||
|
||||
float compressone(const Tile &t, char *block);
|
||||
float compresstwo(const Tile &t, char *block);
|
||||
void decompressone(const char *block, Tile &t);
|
||||
void decompresstwo(const char *block, Tile &t);
|
||||
|
||||
float refinetwo(const Tile &tile, int shapeindex_best, const FltEndpts endpts[NREGIONS_TWO], char *block);
|
||||
float roughtwo(const Tile &tile, int shape, FltEndpts endpts[NREGIONS_TWO]);
|
||||
|
||||
float refineone(const Tile &tile, int shapeindex_best, const FltEndpts endpts[NREGIONS_ONE], char *block);
|
||||
float roughone(const Tile &tile, int shape, FltEndpts endpts[NREGIONS_ONE]);
|
||||
|
||||
bool isone(const char *block);
|
||||
|
||||
}
|
||||
|
||||
#endif // _ZOH_H
|
@ -1,324 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// Utility and common routines
|
||||
|
||||
#include "zoh_utils.h"
|
||||
#include "nvmath/Vector.inl"
|
||||
#include <math.h>
|
||||
|
||||
using namespace nv;
|
||||
using namespace ZOH;
|
||||
|
||||
static const int denom7_weights_64[] = {0, 9, 18, 27, 37, 46, 55, 64}; // divided by 64
|
||||
static const int denom15_weights_64[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64}; // divided by 64
|
||||
|
||||
/*static*/ Format Utils::FORMAT;
|
||||
|
||||
int Utils::lerp(int a, int b, int i, int denom)
|
||||
{
|
||||
nvDebugCheck (denom == 3 || denom == 7 || denom == 15);
|
||||
nvDebugCheck (i >= 0 && i <= denom);
|
||||
|
||||
int round = 32, shift = 6;
|
||||
const int *weights;
|
||||
|
||||
switch(denom)
|
||||
{
|
||||
case 3: denom *= 5; i *= 5; // fall through to case 15
|
||||
case 15: weights = denom15_weights_64; break;
|
||||
case 7: weights = denom7_weights_64; break;
|
||||
default: nvDebugCheck(0);
|
||||
}
|
||||
|
||||
return (a*weights[denom-i] +b*weights[i] + round) >> shift;
|
||||
}
|
||||
|
||||
Vector3 Utils::lerp(const Vector3& a, const Vector3 &b, int i, int denom)
|
||||
{
|
||||
nvDebugCheck (denom == 3 || denom == 7 || denom == 15);
|
||||
nvDebugCheck (i >= 0 && i <= denom);
|
||||
|
||||
int shift = 6;
|
||||
const int *weights;
|
||||
|
||||
switch(denom)
|
||||
{
|
||||
case 3: denom *= 5; i *= 5; // fall through to case 15
|
||||
case 15: weights = denom15_weights_64; break;
|
||||
case 7: weights = denom7_weights_64; break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
|
||||
// no need to round these as this is an exact division
|
||||
return (a*float(weights[denom-i]) +b*float(weights[i])) / float(1 << shift);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
For unsigned f16, clamp the input to [0,F16MAX]. Thus u15.
|
||||
For signed f16, clamp the input to [-F16MAX,F16MAX]. Thus s16.
|
||||
|
||||
The conversions proceed as follows:
|
||||
|
||||
unsigned f16: get bits. if high bit set, clamp to 0, else clamp to F16MAX.
|
||||
signed f16: get bits. extract exp+mantissa and clamp to F16MAX. return -value if sign bit was set, else value
|
||||
unsigned int: get bits. return as a positive value.
|
||||
signed int. get bits. return as a value in -32768..32767.
|
||||
|
||||
The inverse conversions are just the inverse of the above.
|
||||
*/
|
||||
|
||||
// clamp the 3 channels of the input vector to the allowable range based on FORMAT
|
||||
// note that each channel is a float storing the allowable range as a bit pattern converted to float
|
||||
// that is, for unsigned f16 say, we would clamp each channel to the range [0, F16MAX]
|
||||
|
||||
void Utils::clamp(Vector3 &v)
|
||||
{
|
||||
for (int i=0; i<3; ++i)
|
||||
{
|
||||
switch(Utils::FORMAT)
|
||||
{
|
||||
case UNSIGNED_F16:
|
||||
if (v.component[i] < 0.0) v.component[i] = 0;
|
||||
else if (v.component[i] > F16MAX) v.component[i] = F16MAX;
|
||||
break;
|
||||
|
||||
case SIGNED_F16:
|
||||
if (v.component[i] < -F16MAX) v.component[i] = -F16MAX;
|
||||
else if (v.component[i] > F16MAX) v.component[i] = F16MAX;
|
||||
break;
|
||||
|
||||
default:
|
||||
nvUnreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// convert a u16 value to s17 (represented as an int) based on the format expected
|
||||
int Utils::ushort_to_format(unsigned short input)
|
||||
{
|
||||
int out, s;
|
||||
|
||||
// clamp to the valid range we are expecting
|
||||
switch (Utils::FORMAT)
|
||||
{
|
||||
case UNSIGNED_F16:
|
||||
if (input & F16S_MASK) out = 0;
|
||||
else if (input > F16MAX) out = F16MAX;
|
||||
else out = input;
|
||||
break;
|
||||
|
||||
case SIGNED_F16:
|
||||
s = input & F16S_MASK;
|
||||
input &= F16EM_MASK;
|
||||
if (input > F16MAX) out = F16MAX;
|
||||
else out = input;
|
||||
out = s ? -out : out;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// convert a s17 value to u16 based on the format expected
|
||||
unsigned short Utils::format_to_ushort(int input)
|
||||
{
|
||||
unsigned short out;
|
||||
|
||||
// clamp to the valid range we are expecting
|
||||
switch (Utils::FORMAT)
|
||||
{
|
||||
case UNSIGNED_F16:
|
||||
nvDebugCheck (input >= 0 && input <= F16MAX);
|
||||
out = input;
|
||||
break;
|
||||
|
||||
case SIGNED_F16:
|
||||
nvDebugCheck (input >= -F16MAX && input <= F16MAX);
|
||||
// convert to sign-magnitude
|
||||
int s;
|
||||
if (input < 0) { s = F16S_MASK; input = -input; }
|
||||
else { s = 0; }
|
||||
out = s | input;
|
||||
break;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// quantize the input range into equal-sized bins
|
||||
int Utils::quantize(float value, int prec)
|
||||
{
|
||||
int q, ivalue, s;
|
||||
|
||||
nvDebugCheck (prec > 1); // didn't bother to make it work for 1
|
||||
|
||||
value = (float)floor(value + 0.5);
|
||||
|
||||
int bias = (prec > 10) ? ((1<<(prec-1))-1) : 0; // bias precisions 11..16 to get a more accurate quantization
|
||||
|
||||
switch (Utils::FORMAT)
|
||||
{
|
||||
case UNSIGNED_F16:
|
||||
nvDebugCheck (value >= 0 && value <= F16MAX);
|
||||
ivalue = (int)value;
|
||||
q = ((ivalue << prec) + bias) / (F16MAX+1);
|
||||
nvDebugCheck (q >= 0 && q < (1 << prec));
|
||||
break;
|
||||
|
||||
case SIGNED_F16:
|
||||
nvDebugCheck (value >= -F16MAX && value <= F16MAX);
|
||||
// convert to sign-magnitude
|
||||
ivalue = (int)value;
|
||||
if (ivalue < 0) { s = 1; ivalue = -ivalue; } else s = 0;
|
||||
|
||||
q = ((ivalue << (prec-1)) + bias) / (F16MAX+1);
|
||||
if (s)
|
||||
q = -q;
|
||||
nvDebugCheck (q > -(1 << (prec-1)) && q < (1 << (prec-1)));
|
||||
break;
|
||||
}
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
int Utils::finish_unquantize(int q, int prec)
|
||||
{
|
||||
if (Utils::FORMAT == UNSIGNED_F16)
|
||||
return (q * 31) >> 6; // scale the magnitude by 31/64
|
||||
else if (Utils::FORMAT == SIGNED_F16)
|
||||
return (q < 0) ? -(((-q) * 31) >> 5) : (q * 31) >> 5; // scale the magnitude by 31/32
|
||||
else
|
||||
return q;
|
||||
}
|
||||
|
||||
// unquantize each bin to midpoint of original bin range, except
|
||||
// for the end bins which we push to an endpoint of the bin range.
|
||||
// we do this to ensure we can represent all possible original values.
|
||||
// the asymmetric end bins do not affect PSNR for the test images.
|
||||
//
|
||||
// code this function assuming an arbitrary bit pattern as the encoded block
|
||||
int Utils::unquantize(int q, int prec)
|
||||
{
|
||||
int unq, s;
|
||||
|
||||
nvDebugCheck (prec > 1); // not implemented for prec 1
|
||||
|
||||
switch (Utils::FORMAT)
|
||||
{
|
||||
// modify this case to move the multiplication by 31 after interpolation.
|
||||
// Need to use finish_unquantize.
|
||||
|
||||
// since we have 16 bits available, let's unquantize this to 16 bits unsigned
|
||||
// thus the scale factor is [0-7c00)/[0-10000) = 31/64
|
||||
case UNSIGNED_F16:
|
||||
if (prec >= 15)
|
||||
unq = q;
|
||||
else if (q == 0)
|
||||
unq = 0;
|
||||
else if (q == ((1<<prec)-1))
|
||||
unq = U16MAX;
|
||||
else
|
||||
unq = (q * (U16MAX+1) + (U16MAX+1)/2) >> prec;
|
||||
break;
|
||||
|
||||
// here, let's stick with S16 (no apparent quality benefit from going to S17)
|
||||
// range is (-7c00..7c00)/(-8000..8000) = 31/32
|
||||
case SIGNED_F16:
|
||||
// don't remove this test even though it appears equivalent to the code below
|
||||
// as it isn't -- the code below can overflow for prec = 16
|
||||
if (prec >= 16)
|
||||
unq = q;
|
||||
else
|
||||
{
|
||||
if (q < 0) { s = 1; q = -q; } else s = 0;
|
||||
|
||||
if (q == 0)
|
||||
unq = 0;
|
||||
else if (q >= ((1<<(prec-1))-1))
|
||||
unq = s ? -S16MAX : S16MAX;
|
||||
else
|
||||
{
|
||||
unq = (q * (S16MAX+1) + (S16MAX+1)/2) >> (prec-1);
|
||||
if (s)
|
||||
unq = -unq;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return unq;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// pick a norm!
|
||||
#define NORM_EUCLIDEAN 1
|
||||
|
||||
float Utils::norm(const Vector3 &a, const Vector3 &b)
|
||||
{
|
||||
#ifdef NORM_EUCLIDEAN
|
||||
return lengthSquared(a - b);
|
||||
#endif
|
||||
#ifdef NORM_ABS
|
||||
Vector3 err = a - b;
|
||||
return fabs(err.x) + fabs(err.y) + fabs(err.z);
|
||||
#endif
|
||||
}
|
||||
|
||||
// parse <name>[<start>{:<end>}]{,}
|
||||
// the pointer starts here ^
|
||||
// name is 1 or 2 chars and matches field names. start and end are decimal numbers
|
||||
void Utils::parse(const char *encoding, int &ptr, Field &field, int &endbit, int &len)
|
||||
{
|
||||
if (ptr <= 0) return;
|
||||
--ptr;
|
||||
if (encoding[ptr] == ',') --ptr;
|
||||
nvDebugCheck (encoding[ptr] == ']');
|
||||
--ptr;
|
||||
endbit = 0;
|
||||
int scale = 1;
|
||||
while (encoding[ptr] != ':' && encoding[ptr] != '[')
|
||||
{
|
||||
nvDebugCheck(encoding[ptr] >= '0' && encoding[ptr] <= '9');
|
||||
endbit += (encoding[ptr--] - '0') * scale;
|
||||
scale *= 10;
|
||||
}
|
||||
int startbit = 0; scale = 1;
|
||||
if (encoding[ptr] == '[')
|
||||
startbit = endbit;
|
||||
else
|
||||
{
|
||||
ptr--;
|
||||
while (encoding[ptr] != '[')
|
||||
{
|
||||
nvDebugCheck(encoding[ptr] >= '0' && encoding[ptr] <= '9');
|
||||
startbit += (encoding[ptr--] - '0') * scale;
|
||||
scale *= 10;
|
||||
}
|
||||
}
|
||||
len = startbit - endbit + 1; // startbit>=endbit note
|
||||
--ptr;
|
||||
if (encoding[ptr] == 'm') field = FIELD_M;
|
||||
else if (encoding[ptr] == 'd') field = FIELD_D;
|
||||
else {
|
||||
// it's wxyz
|
||||
nvDebugCheck (encoding[ptr] >= 'w' && encoding[ptr] <= 'z');
|
||||
int foo = encoding[ptr--] - 'w';
|
||||
// now it is r g or b
|
||||
if (encoding[ptr] == 'r') foo += 10;
|
||||
else if (encoding[ptr] == 'g') foo += 20;
|
||||
else if (encoding[ptr] == 'b') foo += 30;
|
||||
else nvDebugCheck(0);
|
||||
field = (Field) foo;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,73 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// utility class holding common routines
|
||||
#pragma once
|
||||
#ifndef _ZOH_UTILS_H
|
||||
#define _ZOH_UTILS_H
|
||||
|
||||
#include "nvmath/Vector.h"
|
||||
|
||||
namespace ZOH {
|
||||
|
||||
inline int SIGN_EXTEND(int x, int nb) { return ((((signed(x))&(1<<((nb)-1)))?((~0)<<(nb)):0)|(signed(x))); }
|
||||
|
||||
enum Field {
|
||||
FIELD_M = 1, // mode
|
||||
FIELD_D = 2, // distribution/shape
|
||||
FIELD_RW = 10+0, FIELD_RX = 10+1, FIELD_RY = 10+2, FIELD_RZ = 10+3, // red channel endpoints or deltas
|
||||
FIELD_GW = 20+0, FIELD_GX = 20+1, FIELD_GY = 20+2, FIELD_GZ = 20+3, // green channel endpoints or deltas
|
||||
FIELD_BW = 30+0, FIELD_BX = 30+1, FIELD_BY = 30+2, FIELD_BZ = 30+3, // blue channel endpoints or deltas
|
||||
};
|
||||
|
||||
// some constants
|
||||
static const int F16S_MASK = 0x8000; // f16 sign mask
|
||||
static const int F16EM_MASK = 0x7fff; // f16 exp & mantissa mask
|
||||
static const int U16MAX = 0xffff;
|
||||
static const int S16MIN = -0x8000;
|
||||
static const int S16MAX = 0x7fff;
|
||||
static const int INT16_MASK = 0xffff;
|
||||
static const int F16MAX = 0x7bff; // MAXFLT bit pattern for halfs
|
||||
|
||||
enum Format { UNSIGNED_F16, SIGNED_F16 };
|
||||
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
static Format FORMAT; // this is a global -- we're either handling unsigned or unsigned half values
|
||||
|
||||
// error metrics
|
||||
static float norm(const nv::Vector3 &a, const nv::Vector3 &b);
|
||||
static float mpsnr_norm(const nv::Vector3 &a, int exposure, const nv::Vector3 &b);
|
||||
|
||||
// conversion & clamp
|
||||
static int ushort_to_format(unsigned short input);
|
||||
static unsigned short format_to_ushort(int input);
|
||||
|
||||
// clamp to format
|
||||
static void clamp(nv::Vector3 &v);
|
||||
|
||||
// quantization and unquantization
|
||||
static int finish_unquantize(int q, int prec);
|
||||
static int unquantize(int q, int prec);
|
||||
static int quantize(float value, int prec);
|
||||
|
||||
static void parse(const char *encoding, int &ptr, Field & field, int &endbit, int &len);
|
||||
|
||||
// lerping
|
||||
static int lerp(int a, int b, int i, int denom);
|
||||
static nv::Vector3 lerp(const nv::Vector3 & a, const nv::Vector3 & b, int i, int denom);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // _ZOH_UTILS_H
|
@ -1,799 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// one region zoh compress/decompress code
|
||||
// Thanks to Jacob Munkberg (jacob@cs.lth.se) for the shortcut of using SVD to do the equivalent of principal components analysis
|
||||
|
||||
#include "bits.h"
|
||||
#include "tile.h"
|
||||
#include "zoh.h"
|
||||
#include "zoh_utils.h"
|
||||
|
||||
#include "nvmath/Vector.inl"
|
||||
#include "nvmath/Fitting.h"
|
||||
|
||||
#include <string.h> // strlen
|
||||
#include <float.h> // FLT_MAX
|
||||
|
||||
using namespace nv;
|
||||
using namespace ZOH;
|
||||
|
||||
#define NINDICES 16
|
||||
#define INDEXBITS 4
|
||||
#define HIGH_INDEXBIT (1<<(INDEXBITS-1))
|
||||
#define DENOM (NINDICES-1)
|
||||
|
||||
#define NSHAPES 1
|
||||
|
||||
static const int shapes[NSHAPES] =
|
||||
{
|
||||
0x0000
|
||||
}; // only 1 shape
|
||||
|
||||
#define REGION(x,y,shapeindex) ((shapes[shapeindex]&(1<<(15-(x)-4*(y))))!=0)
|
||||
|
||||
#define POS_TO_X(pos) ((pos)&3)
|
||||
#define POS_TO_Y(pos) (((pos)>>2)&3)
|
||||
|
||||
#define NDELTA 2
|
||||
|
||||
struct Chanpat
|
||||
{
|
||||
int prec[NDELTA]; // precision pattern for one channel
|
||||
};
|
||||
|
||||
struct Pattern
|
||||
{
|
||||
Chanpat chan[NCHANNELS];// allow different bit patterns per channel -- but we still want constant precision per channel
|
||||
int transformed; // if 0, deltas are unsigned and no transform; otherwise, signed and transformed
|
||||
int mode; // associated mode value
|
||||
int modebits; // number of mode bits
|
||||
const char *encoding; // verilog description of encoding for this mode
|
||||
};
|
||||
|
||||
#define MAXMODEBITS 5
|
||||
#define MAXMODES (1<<MAXMODEBITS)
|
||||
|
||||
#define NPATTERNS 4
|
||||
|
||||
static const Pattern patterns[NPATTERNS] =
|
||||
{
|
||||
16,4, 16,4, 16,4, 1, 0x0f, 5, "bw[10],bw[11],bw[12],bw[13],bw[14],bw[15],bx[3:0],gw[10],gw[11],gw[12],gw[13],gw[14],gw[15],gx[3:0],rw[10],rw[11],rw[12],rw[13],rw[14],rw[15],rx[3:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
12,8, 12,8, 12,8, 1, 0x0b, 5, "bw[10],bw[11],bx[7:0],gw[10],gw[11],gx[7:0],rw[10],rw[11],rx[7:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
11,9, 11,9, 11,9, 1, 0x07, 5, "bw[10],bx[8:0],gw[10],gx[8:0],rw[10],rx[8:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
10,10, 10,10, 10,10, 0, 0x03, 5, "bx[9:0],gx[9:0],rx[9:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
};
|
||||
|
||||
// mapping of mode to the corresponding index in pattern
|
||||
static const int mode_to_pat[MAXMODES] = {
|
||||
-1,-1,-1,
|
||||
3, // 0x03
|
||||
-1,-1,-1,
|
||||
2, // 0x07
|
||||
-1,-1,-1,
|
||||
1, // 0x0b
|
||||
-1,-1,-1,
|
||||
0, // 0x0f
|
||||
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
|
||||
};
|
||||
|
||||
#define R_0(ep) (ep)[0].A[i]
|
||||
#define R_1(ep) (ep)[0].B[i]
|
||||
#define MASK(n) ((1<<(n))-1)
|
||||
|
||||
// compress endpoints
|
||||
static void compress_endpts(const IntEndpts in[NREGIONS_ONE], ComprEndpts out[NREGIONS_ONE], const Pattern &p)
|
||||
{
|
||||
if (p.transformed)
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = (R_1(in) - R_0(in)) & MASK(p.chan[i].prec[1]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = R_1(in) & MASK(p.chan[i].prec[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decompress endpoints
|
||||
static void decompress_endpts(const ComprEndpts in[NREGIONS_ONE], IntEndpts out[NREGIONS_ONE], const Pattern &p)
|
||||
{
|
||||
bool issigned = Utils::FORMAT == SIGNED_F16;
|
||||
|
||||
if (p.transformed)
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
|
||||
int t;
|
||||
t = SIGN_EXTEND(R_1(in), p.chan[i].prec[1]);
|
||||
t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
|
||||
R_1(out) = issigned ? SIGN_EXTEND(R_1(in),p.chan[i].prec[1]) : R_1(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void quantize_endpts(const FltEndpts endpts[NREGIONS_ONE], int prec, IntEndpts q_endpts[NREGIONS_ONE])
|
||||
{
|
||||
for (int region = 0; region < NREGIONS_ONE; ++region)
|
||||
{
|
||||
q_endpts[region].A[0] = Utils::quantize(endpts[region].A.x, prec);
|
||||
q_endpts[region].A[1] = Utils::quantize(endpts[region].A.y, prec);
|
||||
q_endpts[region].A[2] = Utils::quantize(endpts[region].A.z, prec);
|
||||
q_endpts[region].B[0] = Utils::quantize(endpts[region].B.x, prec);
|
||||
q_endpts[region].B[1] = Utils::quantize(endpts[region].B.y, prec);
|
||||
q_endpts[region].B[2] = Utils::quantize(endpts[region].B.z, prec);
|
||||
}
|
||||
}
|
||||
|
||||
// swap endpoints as needed to ensure that the indices at index_one and index_one have a 0 high-order bit
|
||||
// index_one is 0 at x=0 y=0 and 15 at x=3 y=3 so y = (index >> 2) & 3 and x = index & 3
|
||||
static void swap_indices(IntEndpts endpts[NREGIONS_ONE], int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex)
|
||||
{
|
||||
int index_positions[NREGIONS_ONE];
|
||||
|
||||
index_positions[0] = 0; // since WLOG we have the high bit of the shapes at 0
|
||||
|
||||
for (int region = 0; region < NREGIONS_ONE; ++region)
|
||||
{
|
||||
int x = index_positions[region] & 3;
|
||||
int y = (index_positions[region] >> 2) & 3;
|
||||
nvDebugCheck(REGION(x,y,shapeindex) == region); // double check the table
|
||||
if (indices[y][x] & HIGH_INDEXBIT)
|
||||
{
|
||||
// high bit is set, swap the endpts and indices for this region
|
||||
int t;
|
||||
for (int i=0; i<NCHANNELS; ++i) { t = endpts[region].A[i]; endpts[region].A[i] = endpts[region].B[i]; endpts[region].B[i] = t; }
|
||||
|
||||
for (int y = 0; y < Tile::TILE_H; y++)
|
||||
for (int x = 0; x < Tile::TILE_W; x++)
|
||||
if (REGION(x,y,shapeindex) == region)
|
||||
indices[y][x] = NINDICES - 1 - indices[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endpoints fit only if the compression was lossless
|
||||
static bool endpts_fit(const IntEndpts orig[NREGIONS_ONE], const ComprEndpts compressed[NREGIONS_ONE], const Pattern &p)
|
||||
{
|
||||
IntEndpts uncompressed[NREGIONS_ONE];
|
||||
|
||||
decompress_endpts(compressed, uncompressed, p);
|
||||
|
||||
for (int j=0; j<NREGIONS_ONE; ++j)
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
if (orig[j].A[i] != uncompressed[j].A[i]) return false;
|
||||
if (orig[j].B[i] != uncompressed[j].B[i]) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void write_header(const ComprEndpts endpts[NREGIONS_ONE], const Pattern &p, Bits &out)
|
||||
{
|
||||
// interpret the verilog backwards and process it
|
||||
int m = p.mode;
|
||||
int rw = endpts[0].A[0], rx = endpts[0].B[0];
|
||||
int gw = endpts[0].A[1], gx = endpts[0].B[1];
|
||||
int bw = endpts[0].A[2], bx = endpts[0].B[2];
|
||||
int ptr = int(strlen(p.encoding));
|
||||
while (ptr)
|
||||
{
|
||||
Field field;
|
||||
int endbit, len;
|
||||
|
||||
// !!!UNDONE: get rid of string parsing!!!
|
||||
Utils::parse(p.encoding, ptr, field, endbit, len);
|
||||
switch(field)
|
||||
{
|
||||
case FIELD_M: out.write( m >> endbit, len); break;
|
||||
case FIELD_RW: out.write(rw >> endbit, len); break;
|
||||
case FIELD_RX: out.write(rx >> endbit, len); break;
|
||||
case FIELD_GW: out.write(gw >> endbit, len); break;
|
||||
case FIELD_GX: out.write(gx >> endbit, len); break;
|
||||
case FIELD_BW: out.write(bw >> endbit, len); break;
|
||||
case FIELD_BX: out.write(bx >> endbit, len); break;
|
||||
|
||||
case FIELD_D:
|
||||
case FIELD_RY:
|
||||
case FIELD_RZ:
|
||||
case FIELD_GY:
|
||||
case FIELD_GZ:
|
||||
case FIELD_BY:
|
||||
case FIELD_BZ:
|
||||
default: nvUnreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_header(Bits &in, ComprEndpts endpts[NREGIONS_ONE], Pattern &p)
|
||||
{
|
||||
// reading isn't quite symmetric with writing -- we don't know the encoding until we decode the mode
|
||||
int mode = in.read(2);
|
||||
if (mode != 0x00 && mode != 0x01)
|
||||
mode = (in.read(3) << 2) | mode;
|
||||
|
||||
int pat_index = mode_to_pat[mode];
|
||||
|
||||
nvDebugCheck (pat_index >= 0 && pat_index < NPATTERNS);
|
||||
nvDebugCheck (in.getptr() == patterns[pat_index].modebits);
|
||||
|
||||
p = patterns[pat_index];
|
||||
|
||||
int d;
|
||||
int rw, rx;
|
||||
int gw, gx;
|
||||
int bw, bx;
|
||||
|
||||
d = 0;
|
||||
rw = rx = 0;
|
||||
gw = gx = 0;
|
||||
bw = bx = 0;
|
||||
|
||||
int ptr = int(strlen(p.encoding));
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
Field field;
|
||||
int endbit, len;
|
||||
|
||||
// !!!UNDONE: get rid of string parsing!!!
|
||||
Utils::parse(p.encoding, ptr, field, endbit, len);
|
||||
|
||||
switch(field)
|
||||
{
|
||||
case FIELD_M: break; // already processed so ignore
|
||||
case FIELD_RW: rw |= in.read(len) << endbit; break;
|
||||
case FIELD_RX: rx |= in.read(len) << endbit; break;
|
||||
case FIELD_GW: gw |= in.read(len) << endbit; break;
|
||||
case FIELD_GX: gx |= in.read(len) << endbit; break;
|
||||
case FIELD_BW: bw |= in.read(len) << endbit; break;
|
||||
case FIELD_BX: bx |= in.read(len) << endbit; break;
|
||||
|
||||
case FIELD_D:
|
||||
case FIELD_RY:
|
||||
case FIELD_RZ:
|
||||
case FIELD_GY:
|
||||
case FIELD_GZ:
|
||||
case FIELD_BY:
|
||||
case FIELD_BZ:
|
||||
default: nvUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
nvDebugCheck (in.getptr() == 128 - 63);
|
||||
|
||||
endpts[0].A[0] = rw; endpts[0].B[0] = rx;
|
||||
endpts[0].A[1] = gw; endpts[0].B[1] = gx;
|
||||
endpts[0].A[2] = bw; endpts[0].B[2] = bx;
|
||||
}
|
||||
|
||||
// compress index 0
|
||||
static void write_indices(const int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex, Bits &out)
|
||||
{
|
||||
for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
|
||||
{
|
||||
int x = POS_TO_X(pos);
|
||||
int y = POS_TO_Y(pos);
|
||||
|
||||
out.write(indices[y][x], INDEXBITS - ((pos == 0) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_block(const ComprEndpts endpts[NREGIONS_ONE], int shapeindex, const Pattern &p, const int indices[Tile::TILE_H][Tile::TILE_W], char *block)
|
||||
{
|
||||
Bits out(block, ZOH::BITSIZE);
|
||||
|
||||
write_header(endpts, p, out);
|
||||
|
||||
write_indices(indices, shapeindex, out);
|
||||
|
||||
nvDebugCheck(out.getptr() == ZOH::BITSIZE);
|
||||
}
|
||||
|
||||
static void generate_palette_quantized(const IntEndpts &endpts, int prec, Vector3 palette[NINDICES])
|
||||
{
|
||||
// scale endpoints
|
||||
int a, b; // really need a IntVector3...
|
||||
|
||||
a = Utils::unquantize(endpts.A[0], prec);
|
||||
b = Utils::unquantize(endpts.B[0], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].x = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
|
||||
a = Utils::unquantize(endpts.A[1], prec);
|
||||
b = Utils::unquantize(endpts.B[1], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].y = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
|
||||
a = Utils::unquantize(endpts.A[2], prec);
|
||||
b = Utils::unquantize(endpts.B[2], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].z = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
}
|
||||
|
||||
// position 0 was compressed
|
||||
static void read_indices(Bits &in, int shapeindex, int indices[Tile::TILE_H][Tile::TILE_W])
|
||||
{
|
||||
for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
|
||||
{
|
||||
int x = POS_TO_X(pos);
|
||||
int y = POS_TO_Y(pos);
|
||||
|
||||
indices[y][x]= in.read(INDEXBITS - ((pos == 0) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
void ZOH::decompressone(const char *block, Tile &t)
|
||||
{
|
||||
Bits in(block, ZOH::BITSIZE);
|
||||
|
||||
Pattern p;
|
||||
IntEndpts endpts[NREGIONS_ONE];
|
||||
ComprEndpts compr_endpts[NREGIONS_ONE];
|
||||
|
||||
read_header(in, compr_endpts, p);
|
||||
int shapeindex = 0; // only one shape
|
||||
|
||||
decompress_endpts(compr_endpts, endpts, p);
|
||||
|
||||
Vector3 palette[NREGIONS_ONE][NINDICES];
|
||||
for (int r = 0; r < NREGIONS_ONE; ++r)
|
||||
generate_palette_quantized(endpts[r], p.chan[0].prec[0], &palette[r][0]);
|
||||
|
||||
// read indices
|
||||
int indices[Tile::TILE_H][Tile::TILE_W];
|
||||
|
||||
read_indices(in, shapeindex, indices);
|
||||
|
||||
nvDebugCheck(in.getptr() == ZOH::BITSIZE);
|
||||
|
||||
// lookup
|
||||
for (int y = 0; y < Tile::TILE_H; y++)
|
||||
for (int x = 0; x < Tile::TILE_W; x++)
|
||||
t.data[y][x] = palette[REGION(x,y,shapeindex)][indices[y][x]];
|
||||
}
|
||||
|
||||
// given a collection of colors and quantized endpoints, generate a palette, choose best entries, and return a single toterr
|
||||
static float map_colors(const Vector3 colors[], const float importance[], int np, const IntEndpts &endpts, int prec)
|
||||
{
|
||||
Vector3 palette[NINDICES];
|
||||
float toterr = 0;
|
||||
Vector3 err;
|
||||
|
||||
generate_palette_quantized(endpts, prec, palette);
|
||||
|
||||
for (int i = 0; i < np; ++i)
|
||||
{
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(colors[i], palette[0]) * importance[i];
|
||||
|
||||
for (int j = 1; j < NINDICES && besterr > 0; ++j)
|
||||
{
|
||||
err = Utils::norm(colors[i], palette[j]) * importance[i];
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
besterr = err;
|
||||
}
|
||||
toterr += besterr;
|
||||
}
|
||||
return toterr;
|
||||
}
|
||||
|
||||
// assign indices given a tile, shape, and quantized endpoints, return toterr for each region
|
||||
static void assign_indices(const Tile &tile, int shapeindex, IntEndpts endpts[NREGIONS_ONE], int prec,
|
||||
int indices[Tile::TILE_H][Tile::TILE_W], float toterr[NREGIONS_ONE])
|
||||
{
|
||||
// build list of possibles
|
||||
Vector3 palette[NREGIONS_ONE][NINDICES];
|
||||
|
||||
for (int region = 0; region < NREGIONS_ONE; ++region)
|
||||
{
|
||||
generate_palette_quantized(endpts[region], prec, &palette[region][0]);
|
||||
toterr[region] = 0;
|
||||
}
|
||||
|
||||
Vector3 err;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
{
|
||||
int region = REGION(x,y,shapeindex);
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(tile.data[y][x], palette[region][0]);
|
||||
indices[y][x] = 0;
|
||||
|
||||
for (int i = 1; i < NINDICES && besterr > 0; ++i)
|
||||
{
|
||||
err = Utils::norm(tile.data[y][x], palette[region][i]);
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
{
|
||||
besterr = err;
|
||||
indices[y][x] = i;
|
||||
}
|
||||
}
|
||||
toterr[region] += besterr;
|
||||
}
|
||||
}
|
||||
|
||||
static float perturb_one(const Vector3 colors[], const float importance[], int np, int ch, int prec, const IntEndpts &old_endpts, IntEndpts &new_endpts,
|
||||
float old_err, int do_b)
|
||||
{
|
||||
// we have the old endpoints: old_endpts
|
||||
// we have the perturbed endpoints: new_endpts
|
||||
// we have the temporary endpoints: temp_endpts
|
||||
|
||||
IntEndpts temp_endpts;
|
||||
float min_err = old_err; // start with the best current error
|
||||
int beststep;
|
||||
|
||||
// copy real endpoints so we can perturb them
|
||||
for (int i=0; i<NCHANNELS; ++i) { temp_endpts.A[i] = new_endpts.A[i] = old_endpts.A[i]; temp_endpts.B[i] = new_endpts.B[i] = old_endpts.B[i]; }
|
||||
|
||||
// do a logarithmic search for the best error for this endpoint (which)
|
||||
for (int step = 1 << (prec-1); step; step >>= 1)
|
||||
{
|
||||
bool improved = false;
|
||||
for (int sign = -1; sign <= 1; sign += 2)
|
||||
{
|
||||
if (do_b == 0)
|
||||
{
|
||||
temp_endpts.A[ch] = new_endpts.A[ch] + sign * step;
|
||||
if (temp_endpts.A[ch] < 0 || temp_endpts.A[ch] >= (1 << prec))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_endpts.B[ch] = new_endpts.B[ch] + sign * step;
|
||||
if (temp_endpts.B[ch] < 0 || temp_endpts.B[ch] >= (1 << prec))
|
||||
continue;
|
||||
}
|
||||
|
||||
float err = map_colors(colors, importance, np, temp_endpts, prec);
|
||||
|
||||
if (err < min_err)
|
||||
{
|
||||
improved = true;
|
||||
min_err = err;
|
||||
beststep = sign * step;
|
||||
}
|
||||
}
|
||||
// if this was an improvement, move the endpoint and continue search from there
|
||||
if (improved)
|
||||
{
|
||||
if (do_b == 0)
|
||||
new_endpts.A[ch] += beststep;
|
||||
else
|
||||
new_endpts.B[ch] += beststep;
|
||||
}
|
||||
}
|
||||
return min_err;
|
||||
}
|
||||
|
||||
static void optimize_one(const Vector3 colors[], const float importance[], int np, float orig_err, const IntEndpts &orig_endpts, int prec, IntEndpts &opt_endpts)
|
||||
{
|
||||
float opt_err = orig_err;
|
||||
for (int ch = 0; ch < NCHANNELS; ++ch)
|
||||
{
|
||||
opt_endpts.A[ch] = orig_endpts.A[ch];
|
||||
opt_endpts.B[ch] = orig_endpts.B[ch];
|
||||
}
|
||||
/*
|
||||
err0 = perturb(rgb0, delta0)
|
||||
err1 = perturb(rgb1, delta1)
|
||||
if (err0 < err1)
|
||||
if (err0 >= initial_error) break
|
||||
rgb0 += delta0
|
||||
next = 1
|
||||
else
|
||||
if (err1 >= initial_error) break
|
||||
rgb1 += delta1
|
||||
next = 0
|
||||
initial_err = map()
|
||||
for (;;)
|
||||
err = perturb(next ? rgb1:rgb0, delta)
|
||||
if (err >= initial_err) break
|
||||
next? rgb1 : rgb0 += delta
|
||||
initial_err = err
|
||||
*/
|
||||
IntEndpts new_a, new_b;
|
||||
IntEndpts new_endpt;
|
||||
int do_b;
|
||||
|
||||
// now optimize each channel separately
|
||||
for (int ch = 0; ch < NCHANNELS; ++ch)
|
||||
{
|
||||
// figure out which endpoint when perturbed gives the most improvement and start there
|
||||
// if we just alternate, we can easily end up in a local minima
|
||||
float err0 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_a, opt_err, 0); // perturb endpt A
|
||||
float err1 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_b, opt_err, 1); // perturb endpt B
|
||||
|
||||
if (err0 < err1)
|
||||
{
|
||||
if (err0 >= opt_err)
|
||||
continue;
|
||||
|
||||
opt_endpts.A[ch] = new_a.A[ch];
|
||||
opt_err = err0;
|
||||
do_b = 1; // do B next
|
||||
}
|
||||
else
|
||||
{
|
||||
if (err1 >= opt_err)
|
||||
continue;
|
||||
opt_endpts.B[ch] = new_b.B[ch];
|
||||
opt_err = err1;
|
||||
do_b = 0; // do A next
|
||||
}
|
||||
|
||||
// now alternate endpoints and keep trying until there is no improvement
|
||||
for (;;)
|
||||
{
|
||||
float err = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_endpt, opt_err, do_b);
|
||||
if (err >= opt_err)
|
||||
break;
|
||||
if (do_b == 0)
|
||||
opt_endpts.A[ch] = new_endpt.A[ch];
|
||||
else
|
||||
opt_endpts.B[ch] = new_endpt.B[ch];
|
||||
opt_err = err;
|
||||
do_b = 1 - do_b; // now move the other endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void optimize_endpts(const Tile &tile, int shapeindex, const float orig_err[NREGIONS_ONE],
|
||||
const IntEndpts orig_endpts[NREGIONS_ONE], int prec, IntEndpts opt_endpts[NREGIONS_ONE])
|
||||
{
|
||||
Vector3 pixels[Tile::TILE_TOTAL];
|
||||
float importance[Tile::TILE_TOTAL];
|
||||
float err = 0;
|
||||
|
||||
for (int region=0; region<NREGIONS_ONE; ++region)
|
||||
{
|
||||
// collect the pixels in the region
|
||||
int np = 0;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++) {
|
||||
for (int x = 0; x < tile.size_x; x++) {
|
||||
if (REGION(x, y, shapeindex) == region) {
|
||||
pixels[np] = tile.data[y][x];
|
||||
importance[np] = tile.importance_map[y][x];
|
||||
++np;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
optimize_one(pixels, importance, np, orig_err[region], orig_endpts[region], prec, opt_endpts[region]);
|
||||
}
|
||||
}
|
||||
|
||||
/* optimization algorithm
|
||||
for each pattern
|
||||
convert endpoints using pattern precision
|
||||
assign indices and get initial error
|
||||
compress indices (and possibly reorder endpoints)
|
||||
transform endpoints
|
||||
if transformed endpoints fit pattern
|
||||
get original endpoints back
|
||||
optimize endpoints, get new endpoints, new indices, and new error // new error will almost always be better
|
||||
compress new indices
|
||||
transform new endpoints
|
||||
if new endpoints fit pattern AND if error is improved
|
||||
emit compressed block with new data
|
||||
else
|
||||
emit compressed block with original data // to try to preserve maximum endpoint precision
|
||||
*/
|
||||
|
||||
float ZOH::refineone(const Tile &tile, int shapeindex_best, const FltEndpts endpts[NREGIONS_ONE], char *block)
|
||||
{
|
||||
float orig_err[NREGIONS_ONE], opt_err[NREGIONS_ONE], orig_toterr, opt_toterr;
|
||||
IntEndpts orig_endpts[NREGIONS_ONE], opt_endpts[NREGIONS_ONE];
|
||||
ComprEndpts compr_orig[NREGIONS_ONE], compr_opt[NREGIONS_ONE];
|
||||
int orig_indices[Tile::TILE_H][Tile::TILE_W], opt_indices[Tile::TILE_H][Tile::TILE_W];
|
||||
|
||||
for (int sp = 0; sp < NPATTERNS; ++sp)
|
||||
{
|
||||
// precisions for all channels need to be the same
|
||||
for (int i=1; i<NCHANNELS; ++i) nvDebugCheck (patterns[sp].chan[0].prec[0] == patterns[sp].chan[i].prec[0]);
|
||||
|
||||
quantize_endpts(endpts, patterns[sp].chan[0].prec[0], orig_endpts);
|
||||
assign_indices(tile, shapeindex_best, orig_endpts, patterns[sp].chan[0].prec[0], orig_indices, orig_err);
|
||||
swap_indices(orig_endpts, orig_indices, shapeindex_best);
|
||||
compress_endpts(orig_endpts, compr_orig, patterns[sp]);
|
||||
if (endpts_fit(orig_endpts, compr_orig, patterns[sp]))
|
||||
{
|
||||
optimize_endpts(tile, shapeindex_best, orig_err, orig_endpts, patterns[sp].chan[0].prec[0], opt_endpts);
|
||||
assign_indices(tile, shapeindex_best, opt_endpts, patterns[sp].chan[0].prec[0], opt_indices, opt_err);
|
||||
swap_indices(opt_endpts, opt_indices, shapeindex_best);
|
||||
compress_endpts(opt_endpts, compr_opt, patterns[sp]);
|
||||
orig_toterr = opt_toterr = 0;
|
||||
for (int i=0; i < NREGIONS_ONE; ++i) { orig_toterr += orig_err[i]; opt_toterr += opt_err[i]; }
|
||||
|
||||
if (endpts_fit(opt_endpts, compr_opt, patterns[sp]) && opt_toterr < orig_toterr)
|
||||
{
|
||||
emit_block(compr_opt, shapeindex_best, patterns[sp], opt_indices, block);
|
||||
return opt_toterr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// either it stopped fitting when we optimized it, or there was no improvement
|
||||
// so go back to the unoptimized endpoints which we know will fit
|
||||
emit_block(compr_orig, shapeindex_best, patterns[sp], orig_indices, block);
|
||||
return orig_toterr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nvAssert (false); // "No candidate found, should never happen (refineone.)";
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
static void generate_palette_unquantized(const FltEndpts endpts[NREGIONS_ONE], Vector3 palette[NREGIONS_ONE][NINDICES])
|
||||
{
|
||||
for (int region = 0; region < NREGIONS_ONE; ++region)
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[region][i] = Utils::lerp(endpts[region].A, endpts[region].B, i, DENOM);
|
||||
}
|
||||
|
||||
// generate a palette from unquantized endpoints, then pick best palette color for all pixels in each region, return toterr for all regions combined
|
||||
static float map_colors(const Tile &tile, int shapeindex, const FltEndpts endpts[NREGIONS_ONE])
|
||||
{
|
||||
// build list of possibles
|
||||
Vector3 palette[NREGIONS_ONE][NINDICES];
|
||||
|
||||
generate_palette_unquantized(endpts, palette);
|
||||
|
||||
float toterr = 0;
|
||||
Vector3 err;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
{
|
||||
int region = REGION(x,y,shapeindex);
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(tile.data[y][x], palette[region][0]) * tile.importance_map[y][x];
|
||||
|
||||
for (int i = 1; i < NINDICES && besterr > 0; ++i)
|
||||
{
|
||||
err = Utils::norm(tile.data[y][x], palette[region][i]) * tile.importance_map[y][x];
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
besterr = err;
|
||||
}
|
||||
toterr += besterr;
|
||||
}
|
||||
return toterr;
|
||||
}
|
||||
|
||||
float ZOH::roughone(const Tile &tile, int shapeindex, FltEndpts endpts[NREGIONS_ONE])
|
||||
{
|
||||
for (int region=0; region<NREGIONS_ONE; ++region)
|
||||
{
|
||||
int np = 0;
|
||||
Vector3 colors[Tile::TILE_TOTAL];
|
||||
Vector3 mean(0,0,0);
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++) {
|
||||
for (int x = 0; x < tile.size_x; x++) {
|
||||
if (REGION(x,y,shapeindex) == region)
|
||||
{
|
||||
colors[np] = tile.data[y][x];
|
||||
mean += tile.data[y][x];
|
||||
++np;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handle simple cases
|
||||
if (np == 0)
|
||||
{
|
||||
Vector3 zero(0,0,0);
|
||||
endpts[region].A = zero;
|
||||
endpts[region].B = zero;
|
||||
continue;
|
||||
}
|
||||
else if (np == 1)
|
||||
{
|
||||
endpts[region].A = colors[0];
|
||||
endpts[region].B = colors[0];
|
||||
continue;
|
||||
}
|
||||
else if (np == 2)
|
||||
{
|
||||
endpts[region].A = colors[0];
|
||||
endpts[region].B = colors[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
mean /= float(np);
|
||||
|
||||
Vector3 direction = Fit::computePrincipalComponent_EigenSolver(np, colors);
|
||||
|
||||
// project each pixel value along the principal direction
|
||||
float minp = FLT_MAX, maxp = -FLT_MAX;
|
||||
for (int i = 0; i < np; i++)
|
||||
{
|
||||
float dp = dot(colors[i]-mean, direction);
|
||||
if (dp < minp) minp = dp;
|
||||
if (dp > maxp) maxp = dp;
|
||||
}
|
||||
|
||||
// choose as endpoints 2 points along the principal direction that span the projections of all of the pixel values
|
||||
endpts[region].A = mean + minp*direction;
|
||||
endpts[region].B = mean + maxp*direction;
|
||||
|
||||
// clamp endpoints
|
||||
// the argument for clamping is that the actual endpoints need to be clamped and thus we need to choose the best
|
||||
// shape based on endpoints being clamped
|
||||
Utils::clamp(endpts[region].A);
|
||||
Utils::clamp(endpts[region].B);
|
||||
}
|
||||
|
||||
return map_colors(tile, shapeindex, endpts);
|
||||
}
|
||||
|
||||
float ZOH::compressone(const Tile &t, char *block)
|
||||
{
|
||||
int shapeindex_best = 0;
|
||||
FltEndpts endptsbest[NREGIONS_ONE], tempendpts[NREGIONS_ONE];
|
||||
float msebest = FLT_MAX;
|
||||
|
||||
/*
|
||||
collect the mse values that are within 5% of the best values
|
||||
optimize each one and choose the best
|
||||
*/
|
||||
// hack for now -- just use the best value WORK
|
||||
for (int i=0; i<NSHAPES && msebest>0.0; ++i)
|
||||
{
|
||||
float mse = roughone(t, i, tempendpts);
|
||||
if (mse < msebest)
|
||||
{
|
||||
msebest = mse;
|
||||
shapeindex_best = i;
|
||||
memcpy(endptsbest, tempendpts, sizeof(endptsbest));
|
||||
}
|
||||
|
||||
}
|
||||
return refineone(t, shapeindex_best, endptsbest, block);
|
||||
}
|
@ -1,883 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// two regions zoh compress/decompress code
|
||||
// Thanks to Jacob Munkberg (jacob@cs.lth.se) for the shortcut of using SVD to do the equivalent of principal components analysis
|
||||
|
||||
/* optimization algorithm
|
||||
|
||||
get initial float endpoints
|
||||
convert endpoints using 16 bit precision, transform, and get bit delta. choose likely endpoint compression candidates.
|
||||
note that there will be 1 or 2 candidates; 2 will be chosen when the delta values are close to the max possible.
|
||||
for each EC candidate in order from max precision to smaller precision
|
||||
convert endpoints using the appropriate precision.
|
||||
optimize the endpoints and minimize square error. save the error and index assignments. apply index compression as well.
|
||||
(thus the endpoints and indices are in final form.)
|
||||
transform and get bit delta.
|
||||
if the bit delta fits, exit
|
||||
if we ended up with no candidates somehow, choose the tail set of EC candidates and retry. this should happen hardly ever.
|
||||
add a state variable to nvDebugCheck we only do this once.
|
||||
convert to bit stream.
|
||||
return the error.
|
||||
|
||||
Global optimization
|
||||
order all tiles based on their errors
|
||||
do something special for high-error tiles
|
||||
the goal here is to try to avoid tiling artifacts. but I think this is a research problem. let's just generate an error image...
|
||||
|
||||
display an image that shows partitioning and precision selected for each tile
|
||||
*/
|
||||
|
||||
#include "bits.h"
|
||||
#include "tile.h"
|
||||
#include "zoh.h"
|
||||
#include "zoh_utils.h"
|
||||
|
||||
#include "nvmath/Fitting.h"
|
||||
#include "nvmath/Vector.inl"
|
||||
|
||||
#include <string.h> // strlen
|
||||
#include <float.h> // FLT_MAX
|
||||
|
||||
using namespace nv;
|
||||
using namespace ZOH;
|
||||
|
||||
#define NINDICES 8
|
||||
#define INDEXBITS 3
|
||||
#define HIGH_INDEXBIT (1<<(INDEXBITS-1))
|
||||
#define DENOM (NINDICES-1)
|
||||
|
||||
// WORK: determine optimal traversal pattern to search for best shape -- what does the error curve look like?
|
||||
// i.e. can we search shapes in a particular order so we can see the global error minima easily and
|
||||
// stop without having to touch all shapes?
|
||||
|
||||
#include "shapes_two.h"
|
||||
// use only the first 32 available shapes
|
||||
#undef NSHAPES
|
||||
#undef SHAPEBITS
|
||||
#define NSHAPES 32
|
||||
#define SHAPEBITS 5
|
||||
|
||||
#define POS_TO_X(pos) ((pos)&3)
|
||||
#define POS_TO_Y(pos) (((pos)>>2)&3)
|
||||
|
||||
#define NDELTA 4
|
||||
|
||||
struct Chanpat
|
||||
{
|
||||
int prec[NDELTA]; // precision pattern for one channel
|
||||
};
|
||||
|
||||
struct Pattern
|
||||
{
|
||||
Chanpat chan[NCHANNELS]; // allow different bit patterns per channel -- but we still want constant precision per channel
|
||||
int transformed; // if 0, deltas are unsigned and no transform; otherwise, signed and transformed
|
||||
int mode; // associated mode value
|
||||
int modebits; // number of mode bits
|
||||
const char *encoding; // verilog description of encoding for this mode
|
||||
};
|
||||
|
||||
#define MAXMODEBITS 5
|
||||
#define MAXMODES (1<<MAXMODEBITS)
|
||||
|
||||
#define NPATTERNS 10
|
||||
|
||||
static const Pattern patterns[NPATTERNS] =
|
||||
{
|
||||
11,5,5,5, 11,4,4,4, 11,4,4,4, 1, 0x02, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bw[10],bx[3:0],gz[3:0],bz[0],gw[10],gx[3:0],gy[3:0],rw[10],rx[4:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
11,4,4,4, 11,5,5,5, 11,4,4,4, 1, 0x06, 5, "d[4:0],bz[3],gy[4],rz[3:0],bz[2],bz[0],ry[3:0],by[3:0],bz[1],bw[10],bx[3:0],gz[3:0],gw[10],gx[4:0],gy[3:0],gz[4],rw[10],rx[3:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
11,4,4,4, 11,4,4,4, 11,5,5,5, 1, 0x0a, 5, "d[4:0],bz[3],bz[4],rz[3:0],bz[2:1],ry[3:0],by[3:0],bw[10],bx[4:0],gz[3:0],bz[0],gw[10],gx[3:0],gy[3:0],by[4],rw[10],rx[3:0],bw[9:0],gw[9:0],rw[9:0],m[4:0]",
|
||||
10,5,5,5, 10,5,5,5, 10,5,5,5, 1, 0x00, 2, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bw[9:0],gw[9:0],rw[9:0],bz[4],by[4],gy[4],m[1:0]",
|
||||
9,5,5,5, 9,5,5,5, 9,5,5,5, 1, 0x0e, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bz[4],bw[8:0],gy[4],gw[8:0],by[4],rw[8:0],m[4:0]",
|
||||
8,6,6,6, 8,5,5,5, 8,5,5,5, 1, 0x12, 5, "d[4:0],rz[5:0],ry[5:0],by[3:0],bz[1],bx[4:0],gz[3:0],bz[0],gx[4:0],gy[3:0],rx[5:0],bz[4:3],bw[7:0],gy[4],bz[2],gw[7:0],by[4],gz[4],rw[7:0],m[4:0]",
|
||||
8,5,5,5, 8,6,6,6, 8,5,5,5, 1, 0x16, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bz[1],bx[4:0],gz[3:0],gx[5:0],gy[3:0],gz[4],rx[4:0],bz[4],gz[5],bw[7:0],gy[4],gy[5],gw[7:0],by[4],bz[0],rw[7:0],m[4:0]",
|
||||
8,5,5,5, 8,5,5,5, 8,6,6,6, 1, 0x1a, 5, "d[4:0],bz[3],rz[4:0],bz[2],ry[4:0],by[3:0],bx[5:0],gz[3:0],bz[0],gx[4:0],gy[3:0],gz[4],rx[4:0],bz[4],bz[5],bw[7:0],gy[4],by[5],gw[7:0],by[4],bz[1],rw[7:0],m[4:0]",
|
||||
7,6,6,6, 7,6,6,6, 7,6,6,6, 1, 0x01, 2, "d[4:0],rz[5:0],ry[5:0],by[3:0],bx[5:0],gz[3:0],gx[5:0],gy[3:0],rx[5:0],bz[4],bz[5],bz[3],bw[6:0],gy[4],bz[2],by[5],gw[6:0],by[4],bz[1:0],rw[6:0],gz[5:4],gy[5],m[1:0]",
|
||||
6,6,6,6, 6,6,6,6, 6,6,6,6, 0, 0x1e, 5, "d[4:0],rz[5:0],ry[5:0],by[3:0],bx[5:0],gz[3:0],gx[5:0],gy[3:0],rx[5:0],bz[4],bz[5],bz[3],gz[5],bw[5:0],gy[4],bz[2],by[5],gy[5],gw[5:0],by[4],bz[1:0],gz[4],rw[5:0],m[4:0]",
|
||||
};
|
||||
|
||||
// mapping of mode to the corresponding index in pattern
|
||||
// UNUSED ZOH MODES are 0x13, 0x17, 0x1b, 0x1f -- return -2 for these
|
||||
static const int mode_to_pat[MAXMODES] = {
|
||||
3, // 0x00
|
||||
8, // 0x01
|
||||
0, // 0x02
|
||||
-1,-1,-1,
|
||||
1, // 0x06
|
||||
-1,-1,-1,
|
||||
2, // 0x0a
|
||||
-1,-1,-1,
|
||||
4, // 0x0e
|
||||
-1,-1,-1,
|
||||
5, // 0x12
|
||||
-2,-1,-1,
|
||||
6, // 0x16
|
||||
-2,-1,-1,
|
||||
7, // 0x1a
|
||||
-2,-1,-1,
|
||||
9, // 0x1e
|
||||
-2
|
||||
};
|
||||
|
||||
#define R_0(ep) (ep)[0].A[i]
|
||||
#define R_1(ep) (ep)[0].B[i]
|
||||
#define R_2(ep) (ep)[1].A[i]
|
||||
#define R_3(ep) (ep)[1].B[i]
|
||||
#define MASK(n) ((1<<(n))-1)
|
||||
|
||||
// compress endpoints
|
||||
static void compress_endpts(const IntEndpts in[NREGIONS_TWO], ComprEndpts out[NREGIONS_TWO], const Pattern &p)
|
||||
{
|
||||
if (p.transformed)
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = (R_1(in) - R_0(in)) & MASK(p.chan[i].prec[1]);
|
||||
R_2(out) = (R_2(in) - R_0(in)) & MASK(p.chan[i].prec[2]);
|
||||
R_3(out) = (R_3(in) - R_0(in)) & MASK(p.chan[i].prec[3]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = R_0(in) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = R_1(in) & MASK(p.chan[i].prec[1]);
|
||||
R_2(out) = R_2(in) & MASK(p.chan[i].prec[2]);
|
||||
R_3(out) = R_3(in) & MASK(p.chan[i].prec[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// decompress endpoints
|
||||
static void decompress_endpts(const ComprEndpts in[NREGIONS_TWO], IntEndpts out[NREGIONS_TWO], const Pattern &p)
|
||||
{
|
||||
bool issigned = Utils::FORMAT == SIGNED_F16;
|
||||
|
||||
if (p.transformed)
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
|
||||
int t;
|
||||
t = SIGN_EXTEND(R_1(in), p.chan[i].prec[1]);
|
||||
t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
|
||||
R_1(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
|
||||
t = SIGN_EXTEND(R_2(in), p.chan[i].prec[2]);
|
||||
t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
|
||||
R_2(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
|
||||
t = SIGN_EXTEND(R_3(in), p.chan[i].prec[3]);
|
||||
t = (t + R_0(in)) & MASK(p.chan[i].prec[0]);
|
||||
R_3(out) = issigned ? SIGN_EXTEND(t,p.chan[i].prec[0]) : t;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
R_0(out) = issigned ? SIGN_EXTEND(R_0(in),p.chan[i].prec[0]) : R_0(in);
|
||||
R_1(out) = issigned ? SIGN_EXTEND(R_1(in),p.chan[i].prec[1]) : R_1(in);
|
||||
R_2(out) = issigned ? SIGN_EXTEND(R_2(in),p.chan[i].prec[2]) : R_2(in);
|
||||
R_3(out) = issigned ? SIGN_EXTEND(R_3(in),p.chan[i].prec[3]) : R_3(in);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void quantize_endpts(const FltEndpts endpts[NREGIONS_TWO], int prec, IntEndpts q_endpts[NREGIONS_TWO])
|
||||
{
|
||||
for (int region = 0; region < NREGIONS_TWO; ++region)
|
||||
{
|
||||
q_endpts[region].A[0] = Utils::quantize(endpts[region].A.x, prec);
|
||||
q_endpts[region].A[1] = Utils::quantize(endpts[region].A.y, prec);
|
||||
q_endpts[region].A[2] = Utils::quantize(endpts[region].A.z, prec);
|
||||
q_endpts[region].B[0] = Utils::quantize(endpts[region].B.x, prec);
|
||||
q_endpts[region].B[1] = Utils::quantize(endpts[region].B.y, prec);
|
||||
q_endpts[region].B[2] = Utils::quantize(endpts[region].B.z, prec);
|
||||
}
|
||||
}
|
||||
|
||||
// swap endpoints as needed to ensure that the indices at index_positions have a 0 high-order bit
|
||||
static void swap_indices(IntEndpts endpts[NREGIONS_TWO], int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex)
|
||||
{
|
||||
for (int region = 0; region < NREGIONS_TWO; ++region)
|
||||
{
|
||||
int position = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,region);
|
||||
|
||||
int x = POS_TO_X(position);
|
||||
int y = POS_TO_Y(position);
|
||||
nvDebugCheck(REGION(x,y,shapeindex) == region); // double check the table
|
||||
if (indices[y][x] & HIGH_INDEXBIT)
|
||||
{
|
||||
// high bit is set, swap the endpts and indices for this region
|
||||
int t;
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
t = endpts[region].A[i]; endpts[region].A[i] = endpts[region].B[i]; endpts[region].B[i] = t;
|
||||
}
|
||||
|
||||
for (int y = 0; y < Tile::TILE_H; y++)
|
||||
for (int x = 0; x < Tile::TILE_W; x++)
|
||||
if (REGION(x,y,shapeindex) == region)
|
||||
indices[y][x] = NINDICES - 1 - indices[y][x];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// endpoints fit only if the compression was lossless
|
||||
static bool endpts_fit(const IntEndpts orig[NREGIONS_TWO], const ComprEndpts compressed[NREGIONS_TWO], const Pattern &p)
|
||||
{
|
||||
IntEndpts uncompressed[NREGIONS_TWO];
|
||||
|
||||
decompress_endpts(compressed, uncompressed, p);
|
||||
|
||||
for (int j=0; j<NREGIONS_TWO; ++j)
|
||||
{
|
||||
for (int i=0; i<NCHANNELS; ++i)
|
||||
{
|
||||
if (orig[j].A[i] != uncompressed[j].A[i]) return false;
|
||||
if (orig[j].B[i] != uncompressed[j].B[i]) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void write_header(const ComprEndpts endpts[NREGIONS_TWO], int shapeindex, const Pattern &p, Bits &out)
|
||||
{
|
||||
// interpret the verilog backwards and process it
|
||||
int m = p.mode;
|
||||
int d = shapeindex;
|
||||
int rw = endpts[0].A[0], rx = endpts[0].B[0], ry = endpts[1].A[0], rz = endpts[1].B[0];
|
||||
int gw = endpts[0].A[1], gx = endpts[0].B[1], gy = endpts[1].A[1], gz = endpts[1].B[1];
|
||||
int bw = endpts[0].A[2], bx = endpts[0].B[2], by = endpts[1].A[2], bz = endpts[1].B[2];
|
||||
int ptr = int(strlen(p.encoding));
|
||||
while (ptr)
|
||||
{
|
||||
Field field;
|
||||
int endbit, len;
|
||||
|
||||
// !!!UNDONE: get rid of string parsing!!!
|
||||
Utils::parse(p.encoding, ptr, field, endbit, len);
|
||||
switch(field)
|
||||
{
|
||||
case FIELD_M: out.write( m >> endbit, len); break;
|
||||
case FIELD_D: out.write( d >> endbit, len); break;
|
||||
case FIELD_RW: out.write(rw >> endbit, len); break;
|
||||
case FIELD_RX: out.write(rx >> endbit, len); break;
|
||||
case FIELD_RY: out.write(ry >> endbit, len); break;
|
||||
case FIELD_RZ: out.write(rz >> endbit, len); break;
|
||||
case FIELD_GW: out.write(gw >> endbit, len); break;
|
||||
case FIELD_GX: out.write(gx >> endbit, len); break;
|
||||
case FIELD_GY: out.write(gy >> endbit, len); break;
|
||||
case FIELD_GZ: out.write(gz >> endbit, len); break;
|
||||
case FIELD_BW: out.write(bw >> endbit, len); break;
|
||||
case FIELD_BX: out.write(bx >> endbit, len); break;
|
||||
case FIELD_BY: out.write(by >> endbit, len); break;
|
||||
case FIELD_BZ: out.write(bz >> endbit, len); break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool read_header(Bits &in, ComprEndpts endpts[NREGIONS_TWO], int &shapeindex, Pattern &p)
|
||||
{
|
||||
// reading isn't quite symmetric with writing -- we don't know the encoding until we decode the mode
|
||||
int mode = in.read(2);
|
||||
if (mode != 0x00 && mode != 0x01)
|
||||
mode = (in.read(3) << 2) | mode;
|
||||
|
||||
int pat_index = mode_to_pat[mode];
|
||||
|
||||
if (pat_index == -2)
|
||||
return false; // reserved mode found
|
||||
|
||||
nvDebugCheck (pat_index >= 0 && pat_index < NPATTERNS);
|
||||
nvDebugCheck (in.getptr() == patterns[pat_index].modebits);
|
||||
|
||||
p = patterns[pat_index];
|
||||
|
||||
int d;
|
||||
int rw, rx, ry, rz;
|
||||
int gw, gx, gy, gz;
|
||||
int bw, bx, by, bz;
|
||||
|
||||
d = 0;
|
||||
rw = rx = ry = rz = 0;
|
||||
gw = gx = gy = gz = 0;
|
||||
bw = bx = by = bz = 0;
|
||||
|
||||
int ptr = int(strlen(p.encoding));
|
||||
|
||||
while (ptr)
|
||||
{
|
||||
Field field;
|
||||
int endbit, len;
|
||||
|
||||
// !!!UNDONE: get rid of string parsing!!!
|
||||
Utils::parse(p.encoding, ptr, field, endbit, len);
|
||||
|
||||
switch(field)
|
||||
{
|
||||
case FIELD_M: break; // already processed so ignore
|
||||
case FIELD_D: d |= in.read(len) << endbit; break;
|
||||
case FIELD_RW: rw |= in.read(len) << endbit; break;
|
||||
case FIELD_RX: rx |= in.read(len) << endbit; break;
|
||||
case FIELD_RY: ry |= in.read(len) << endbit; break;
|
||||
case FIELD_RZ: rz |= in.read(len) << endbit; break;
|
||||
case FIELD_GW: gw |= in.read(len) << endbit; break;
|
||||
case FIELD_GX: gx |= in.read(len) << endbit; break;
|
||||
case FIELD_GY: gy |= in.read(len) << endbit; break;
|
||||
case FIELD_GZ: gz |= in.read(len) << endbit; break;
|
||||
case FIELD_BW: bw |= in.read(len) << endbit; break;
|
||||
case FIELD_BX: bx |= in.read(len) << endbit; break;
|
||||
case FIELD_BY: by |= in.read(len) << endbit; break;
|
||||
case FIELD_BZ: bz |= in.read(len) << endbit; break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
nvDebugCheck (in.getptr() == 128 - 46);
|
||||
|
||||
shapeindex = d;
|
||||
endpts[0].A[0] = rw; endpts[0].B[0] = rx; endpts[1].A[0] = ry; endpts[1].B[0] = rz;
|
||||
endpts[0].A[1] = gw; endpts[0].B[1] = gx; endpts[1].A[1] = gy; endpts[1].B[1] = gz;
|
||||
endpts[0].A[2] = bw; endpts[0].B[2] = bx; endpts[1].A[2] = by; endpts[1].B[2] = bz;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void write_indices(const int indices[Tile::TILE_H][Tile::TILE_W], int shapeindex, Bits &out)
|
||||
{
|
||||
int positions[NREGIONS_TWO];
|
||||
|
||||
for (int r = 0; r < NREGIONS_TWO; ++r)
|
||||
positions[r] = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,r);
|
||||
|
||||
for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
|
||||
{
|
||||
int x = POS_TO_X(pos);
|
||||
int y = POS_TO_Y(pos);
|
||||
|
||||
bool match = false;
|
||||
|
||||
for (int r = 0; r < NREGIONS_TWO; ++r)
|
||||
if (positions[r] == pos) { match = true; break; }
|
||||
|
||||
out.write(indices[y][x], INDEXBITS - (match ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
static void emit_block(const ComprEndpts compr_endpts[NREGIONS_TWO], int shapeindex, const Pattern &p, const int indices[Tile::TILE_H][Tile::TILE_W], char *block)
|
||||
{
|
||||
Bits out(block, ZOH::BITSIZE);
|
||||
|
||||
write_header(compr_endpts, shapeindex, p, out);
|
||||
|
||||
write_indices(indices, shapeindex, out);
|
||||
|
||||
nvDebugCheck(out.getptr() == ZOH::BITSIZE);
|
||||
}
|
||||
|
||||
static void generate_palette_quantized(const IntEndpts &endpts, int prec, Vector3 palette[NINDICES])
|
||||
{
|
||||
// scale endpoints
|
||||
int a, b; // really need a IntVector3...
|
||||
|
||||
a = Utils::unquantize(endpts.A[0], prec);
|
||||
b = Utils::unquantize(endpts.B[0], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].x = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
|
||||
a = Utils::unquantize(endpts.A[1], prec);
|
||||
b = Utils::unquantize(endpts.B[1], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].y = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
|
||||
a = Utils::unquantize(endpts.A[2], prec);
|
||||
b = Utils::unquantize(endpts.B[2], prec);
|
||||
|
||||
// interpolate
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[i].z = float(Utils::finish_unquantize(Utils::lerp(a, b, i, DENOM), prec));
|
||||
}
|
||||
|
||||
static void read_indices(Bits &in, int shapeindex, int indices[Tile::TILE_H][Tile::TILE_W])
|
||||
{
|
||||
int positions[NREGIONS_TWO];
|
||||
|
||||
for (int r = 0; r < NREGIONS_TWO; ++r)
|
||||
positions[r] = SHAPEINDEX_TO_COMPRESSED_INDICES(shapeindex,r);
|
||||
|
||||
for (int pos = 0; pos < Tile::TILE_TOTAL; ++pos)
|
||||
{
|
||||
int x = POS_TO_X(pos);
|
||||
int y = POS_TO_Y(pos);
|
||||
|
||||
bool match = false;
|
||||
|
||||
for (int r = 0; r < NREGIONS_TWO; ++r)
|
||||
if (positions[r] == pos) { match = true; break; }
|
||||
|
||||
indices[y][x]= in.read(INDEXBITS - (match ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
void ZOH::decompresstwo(const char *block, Tile &t)
|
||||
{
|
||||
Bits in(block, ZOH::BITSIZE);
|
||||
|
||||
Pattern p;
|
||||
IntEndpts endpts[NREGIONS_TWO];
|
||||
ComprEndpts compr_endpts[NREGIONS_TWO];
|
||||
int shapeindex;
|
||||
|
||||
if (!read_header(in, compr_endpts, shapeindex, p))
|
||||
{
|
||||
// reserved mode, return all zeroes
|
||||
for (int y = 0; y < Tile::TILE_H; y++)
|
||||
for (int x = 0; x < Tile::TILE_W; x++)
|
||||
t.data[y][x] = Vector3(0.0f);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
decompress_endpts(compr_endpts, endpts, p);
|
||||
|
||||
Vector3 palette[NREGIONS_TWO][NINDICES];
|
||||
for (int r = 0; r < NREGIONS_TWO; ++r)
|
||||
generate_palette_quantized(endpts[r], p.chan[0].prec[0], &palette[r][0]);
|
||||
|
||||
int indices[Tile::TILE_H][Tile::TILE_W];
|
||||
|
||||
read_indices(in, shapeindex, indices);
|
||||
|
||||
nvDebugCheck(in.getptr() == ZOH::BITSIZE);
|
||||
|
||||
// lookup
|
||||
for (int y = 0; y < Tile::TILE_H; y++)
|
||||
for (int x = 0; x < Tile::TILE_W; x++)
|
||||
t.data[y][x] = palette[REGION(x,y,shapeindex)][indices[y][x]];
|
||||
}
|
||||
|
||||
// given a collection of colors and quantized endpoints, generate a palette, choose best entries, and return a single toterr
|
||||
static float map_colors(const Vector3 colors[], const float importance[], int np, const IntEndpts &endpts, int prec)
|
||||
{
|
||||
Vector3 palette[NINDICES];
|
||||
float toterr = 0;
|
||||
Vector3 err;
|
||||
|
||||
generate_palette_quantized(endpts, prec, palette);
|
||||
|
||||
for (int i = 0; i < np; ++i)
|
||||
{
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(colors[i], palette[0]) * importance[i];
|
||||
|
||||
for (int j = 1; j < NINDICES && besterr > 0; ++j)
|
||||
{
|
||||
err = Utils::norm(colors[i], palette[j]) * importance[i];
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
besterr = err;
|
||||
}
|
||||
toterr += besterr;
|
||||
}
|
||||
return toterr;
|
||||
}
|
||||
|
||||
// assign indices given a tile, shape, and quantized endpoints, return toterr for each region
|
||||
static void assign_indices(const Tile &tile, int shapeindex, IntEndpts endpts[NREGIONS_TWO], int prec,
|
||||
int indices[Tile::TILE_H][Tile::TILE_W], float toterr[NREGIONS_TWO])
|
||||
{
|
||||
// build list of possibles
|
||||
Vector3 palette[NREGIONS_TWO][NINDICES];
|
||||
|
||||
for (int region = 0; region < NREGIONS_TWO; ++region)
|
||||
{
|
||||
generate_palette_quantized(endpts[region], prec, &palette[region][0]);
|
||||
toterr[region] = 0;
|
||||
}
|
||||
|
||||
Vector3 err;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
{
|
||||
int region = REGION(x,y,shapeindex);
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(tile.data[y][x], palette[region][0]);
|
||||
indices[y][x] = 0;
|
||||
|
||||
for (int i = 1; i < NINDICES && besterr > 0; ++i)
|
||||
{
|
||||
err = Utils::norm(tile.data[y][x], palette[region][i]);
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
{
|
||||
besterr = err;
|
||||
indices[y][x] = i;
|
||||
}
|
||||
}
|
||||
toterr[region] += besterr;
|
||||
}
|
||||
}
|
||||
|
||||
static float perturb_one(const Vector3 colors[], const float importance[], int np, int ch, int prec, const IntEndpts &old_endpts, IntEndpts &new_endpts,
|
||||
float old_err, int do_b)
|
||||
{
|
||||
// we have the old endpoints: old_endpts
|
||||
// we have the perturbed endpoints: new_endpts
|
||||
// we have the temporary endpoints: temp_endpts
|
||||
|
||||
IntEndpts temp_endpts;
|
||||
float min_err = old_err; // start with the best current error
|
||||
int beststep;
|
||||
|
||||
// copy real endpoints so we can perturb them
|
||||
for (int i=0; i<NCHANNELS; ++i) { temp_endpts.A[i] = new_endpts.A[i] = old_endpts.A[i]; temp_endpts.B[i] = new_endpts.B[i] = old_endpts.B[i]; }
|
||||
|
||||
// do a logarithmic search for the best error for this endpoint (which)
|
||||
for (int step = 1 << (prec-1); step; step >>= 1)
|
||||
{
|
||||
bool improved = false;
|
||||
for (int sign = -1; sign <= 1; sign += 2)
|
||||
{
|
||||
if (do_b == 0)
|
||||
{
|
||||
temp_endpts.A[ch] = new_endpts.A[ch] + sign * step;
|
||||
if (temp_endpts.A[ch] < 0 || temp_endpts.A[ch] >= (1 << prec))
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_endpts.B[ch] = new_endpts.B[ch] + sign * step;
|
||||
if (temp_endpts.B[ch] < 0 || temp_endpts.B[ch] >= (1 << prec))
|
||||
continue;
|
||||
}
|
||||
|
||||
float err = map_colors(colors, importance, np, temp_endpts, prec);
|
||||
|
||||
if (err < min_err)
|
||||
{
|
||||
improved = true;
|
||||
min_err = err;
|
||||
beststep = sign * step;
|
||||
}
|
||||
}
|
||||
// if this was an improvement, move the endpoint and continue search from there
|
||||
if (improved)
|
||||
{
|
||||
if (do_b == 0)
|
||||
new_endpts.A[ch] += beststep;
|
||||
else
|
||||
new_endpts.B[ch] += beststep;
|
||||
}
|
||||
}
|
||||
return min_err;
|
||||
}
|
||||
|
||||
static void optimize_one(const Vector3 colors[], const float importance[], int np, float orig_err, const IntEndpts &orig_endpts, int prec, IntEndpts &opt_endpts)
|
||||
{
|
||||
float opt_err = orig_err;
|
||||
for (int ch = 0; ch < NCHANNELS; ++ch)
|
||||
{
|
||||
opt_endpts.A[ch] = orig_endpts.A[ch];
|
||||
opt_endpts.B[ch] = orig_endpts.B[ch];
|
||||
}
|
||||
/*
|
||||
err0 = perturb(rgb0, delta0)
|
||||
err1 = perturb(rgb1, delta1)
|
||||
if (err0 < err1)
|
||||
if (err0 >= initial_error) break
|
||||
rgb0 += delta0
|
||||
next = 1
|
||||
else
|
||||
if (err1 >= initial_error) break
|
||||
rgb1 += delta1
|
||||
next = 0
|
||||
initial_err = map()
|
||||
for (;;)
|
||||
err = perturb(next ? rgb1:rgb0, delta)
|
||||
if (err >= initial_err) break
|
||||
next? rgb1 : rgb0 += delta
|
||||
initial_err = err
|
||||
*/
|
||||
IntEndpts new_a, new_b;
|
||||
IntEndpts new_endpt;
|
||||
int do_b;
|
||||
|
||||
// now optimize each channel separately
|
||||
for (int ch = 0; ch < NCHANNELS; ++ch)
|
||||
{
|
||||
// figure out which endpoint when perturbed gives the most improvement and start there
|
||||
// if we just alternate, we can easily end up in a local minima
|
||||
float err0 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_a, opt_err, 0); // perturb endpt A
|
||||
float err1 = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_b, opt_err, 1); // perturb endpt B
|
||||
|
||||
if (err0 < err1)
|
||||
{
|
||||
if (err0 >= opt_err)
|
||||
continue;
|
||||
|
||||
opt_endpts.A[ch] = new_a.A[ch];
|
||||
opt_err = err0;
|
||||
do_b = 1; // do B next
|
||||
}
|
||||
else
|
||||
{
|
||||
if (err1 >= opt_err)
|
||||
continue;
|
||||
opt_endpts.B[ch] = new_b.B[ch];
|
||||
opt_err = err1;
|
||||
do_b = 0; // do A next
|
||||
}
|
||||
|
||||
// now alternate endpoints and keep trying until there is no improvement
|
||||
for (;;)
|
||||
{
|
||||
float err = perturb_one(colors, importance, np, ch, prec, opt_endpts, new_endpt, opt_err, do_b);
|
||||
if (err >= opt_err)
|
||||
break;
|
||||
if (do_b == 0)
|
||||
opt_endpts.A[ch] = new_endpt.A[ch];
|
||||
else
|
||||
opt_endpts.B[ch] = new_endpt.B[ch];
|
||||
opt_err = err;
|
||||
do_b = 1 - do_b; // now move the other endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void optimize_endpts(const Tile &tile, int shapeindex, const float orig_err[NREGIONS_TWO],
|
||||
const IntEndpts orig_endpts[NREGIONS_TWO], int prec, IntEndpts opt_endpts[NREGIONS_TWO])
|
||||
{
|
||||
Vector3 pixels[Tile::TILE_TOTAL];
|
||||
float importance[Tile::TILE_TOTAL];
|
||||
float err = 0;
|
||||
|
||||
for (int region=0; region<NREGIONS_TWO; ++region)
|
||||
{
|
||||
// collect the pixels in the region
|
||||
int np = 0;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
if (REGION(x,y,shapeindex) == region)
|
||||
{
|
||||
pixels[np] = tile.data[y][x];
|
||||
importance[np] = tile.importance_map[y][x];
|
||||
++np;
|
||||
}
|
||||
|
||||
optimize_one(pixels, importance, np, orig_err[region], orig_endpts[region], prec, opt_endpts[region]);
|
||||
}
|
||||
}
|
||||
|
||||
/* optimization algorithm
|
||||
for each pattern
|
||||
convert endpoints using pattern precision
|
||||
assign indices and get initial error
|
||||
compress indices (and possibly reorder endpoints)
|
||||
transform endpoints
|
||||
if transformed endpoints fit pattern
|
||||
get original endpoints back
|
||||
optimize endpoints, get new endpoints, new indices, and new error // new error will almost always be better
|
||||
compress new indices
|
||||
transform new endpoints
|
||||
if new endpoints fit pattern AND if error is improved
|
||||
emit compressed block with new data
|
||||
else
|
||||
emit compressed block with original data // to try to preserve maximum endpoint precision
|
||||
*/
|
||||
|
||||
float ZOH::refinetwo(const Tile &tile, int shapeindex_best, const FltEndpts endpts[NREGIONS_TWO], char *block)
|
||||
{
|
||||
float orig_err[NREGIONS_TWO], opt_err[NREGIONS_TWO], orig_toterr, opt_toterr;
|
||||
IntEndpts orig_endpts[NREGIONS_TWO], opt_endpts[NREGIONS_TWO];
|
||||
ComprEndpts compr_orig[NREGIONS_TWO], compr_opt[NREGIONS_TWO];
|
||||
int orig_indices[Tile::TILE_H][Tile::TILE_W], opt_indices[Tile::TILE_H][Tile::TILE_W];
|
||||
|
||||
for (int sp = 0; sp < NPATTERNS; ++sp)
|
||||
{
|
||||
// precisions for all channels need to be the same
|
||||
for (int i=1; i<NCHANNELS; ++i) nvDebugCheck (patterns[sp].chan[0].prec[0] == patterns[sp].chan[i].prec[0]);
|
||||
|
||||
quantize_endpts(endpts, patterns[sp].chan[0].prec[0], orig_endpts);
|
||||
assign_indices(tile, shapeindex_best, orig_endpts, patterns[sp].chan[0].prec[0], orig_indices, orig_err);
|
||||
swap_indices(orig_endpts, orig_indices, shapeindex_best);
|
||||
compress_endpts(orig_endpts, compr_orig, patterns[sp]);
|
||||
if (endpts_fit(orig_endpts, compr_orig, patterns[sp]))
|
||||
{
|
||||
optimize_endpts(tile, shapeindex_best, orig_err, orig_endpts, patterns[sp].chan[0].prec[0], opt_endpts);
|
||||
assign_indices(tile, shapeindex_best, opt_endpts, patterns[sp].chan[0].prec[0], opt_indices, opt_err);
|
||||
swap_indices(opt_endpts, opt_indices, shapeindex_best);
|
||||
compress_endpts(opt_endpts, compr_opt, patterns[sp]);
|
||||
orig_toterr = opt_toterr = 0;
|
||||
for (int i=0; i < NREGIONS_TWO; ++i) { orig_toterr += orig_err[i]; opt_toterr += opt_err[i]; }
|
||||
if (endpts_fit(opt_endpts, compr_opt, patterns[sp]) && opt_toterr < orig_toterr)
|
||||
{
|
||||
emit_block(compr_opt, shapeindex_best, patterns[sp], opt_indices, block);
|
||||
return opt_toterr;
|
||||
}
|
||||
else
|
||||
{
|
||||
// either it stopped fitting when we optimized it, or there was no improvement
|
||||
// so go back to the unoptimized endpoints which we know will fit
|
||||
emit_block(compr_orig, shapeindex_best, patterns[sp], orig_indices, block);
|
||||
return orig_toterr;
|
||||
}
|
||||
}
|
||||
}
|
||||
nvAssert(false); //throw "No candidate found, should never happen (refinetwo.)";
|
||||
return FLT_MAX;
|
||||
}
|
||||
|
||||
static void generate_palette_unquantized(const FltEndpts endpts[NREGIONS_TWO], Vector3 palette[NREGIONS_TWO][NINDICES])
|
||||
{
|
||||
for (int region = 0; region < NREGIONS_TWO; ++region)
|
||||
for (int i = 0; i < NINDICES; ++i)
|
||||
palette[region][i] = Utils::lerp(endpts[region].A, endpts[region].B, i, DENOM);
|
||||
}
|
||||
|
||||
// generate a palette from unquantized endpoints, then pick best palette color for all pixels in each region, return toterr for all regions combined
|
||||
static float map_colors(const Tile &tile, int shapeindex, const FltEndpts endpts[NREGIONS_TWO])
|
||||
{
|
||||
// build list of possibles
|
||||
Vector3 palette[NREGIONS_TWO][NINDICES];
|
||||
|
||||
generate_palette_unquantized(endpts, palette);
|
||||
|
||||
float toterr = 0;
|
||||
Vector3 err;
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
{
|
||||
int region = REGION(x,y,shapeindex);
|
||||
float err, besterr;
|
||||
|
||||
besterr = Utils::norm(tile.data[y][x], palette[region][0]) * tile.importance_map[y][x];
|
||||
|
||||
for (int i = 1; i < NINDICES && besterr > 0; ++i)
|
||||
{
|
||||
err = Utils::norm(tile.data[y][x], palette[region][i]) * tile.importance_map[y][x];
|
||||
|
||||
if (err > besterr) // error increased, so we're done searching
|
||||
break;
|
||||
if (err < besterr)
|
||||
besterr = err;
|
||||
}
|
||||
toterr += besterr;
|
||||
}
|
||||
return toterr;
|
||||
}
|
||||
|
||||
float ZOH::roughtwo(const Tile &tile, int shapeindex, FltEndpts endpts[NREGIONS_TWO])
|
||||
{
|
||||
for (int region=0; region<NREGIONS_TWO; ++region)
|
||||
{
|
||||
int np = 0;
|
||||
Vector3 colors[Tile::TILE_TOTAL];
|
||||
Vector3 mean(0,0,0);
|
||||
|
||||
for (int y = 0; y < tile.size_y; y++)
|
||||
for (int x = 0; x < tile.size_x; x++)
|
||||
if (REGION(x,y,shapeindex) == region)
|
||||
{
|
||||
colors[np] = tile.data[y][x];
|
||||
mean += tile.data[y][x];
|
||||
++np;
|
||||
}
|
||||
|
||||
// handle simple cases
|
||||
if (np == 0)
|
||||
{
|
||||
Vector3 zero(0,0,0);
|
||||
endpts[region].A = zero;
|
||||
endpts[region].B = zero;
|
||||
continue;
|
||||
}
|
||||
else if (np == 1)
|
||||
{
|
||||
endpts[region].A = colors[0];
|
||||
endpts[region].B = colors[0];
|
||||
continue;
|
||||
}
|
||||
else if (np == 2)
|
||||
{
|
||||
endpts[region].A = colors[0];
|
||||
endpts[region].B = colors[1];
|
||||
continue;
|
||||
}
|
||||
|
||||
mean /= float(np);
|
||||
|
||||
Vector3 direction = Fit::computePrincipalComponent_EigenSolver(np, colors);
|
||||
|
||||
// project each pixel value along the principal direction
|
||||
float minp = FLT_MAX, maxp = -FLT_MAX;
|
||||
for (int i = 0; i < np; i++)
|
||||
{
|
||||
float dp = dot(colors[i]-mean, direction);
|
||||
if (dp < minp) minp = dp;
|
||||
if (dp > maxp) maxp = dp;
|
||||
}
|
||||
|
||||
// choose as endpoints 2 points along the principal direction that span the projections of all of the pixel values
|
||||
endpts[region].A = mean + minp*direction;
|
||||
endpts[region].B = mean + maxp*direction;
|
||||
|
||||
// clamp endpoints
|
||||
// the argument for clamping is that the actual endpoints need to be clamped and thus we need to choose the best
|
||||
// shape based on endpoints being clamped
|
||||
Utils::clamp(endpts[region].A);
|
||||
Utils::clamp(endpts[region].B);
|
||||
}
|
||||
|
||||
return map_colors(tile, shapeindex, endpts);
|
||||
}
|
||||
|
||||
float ZOH::compresstwo(const Tile &t, char *block)
|
||||
{
|
||||
int shapeindex_best = 0;
|
||||
FltEndpts endptsbest[NREGIONS_TWO], tempendpts[NREGIONS_TWO];
|
||||
float msebest = FLT_MAX;
|
||||
|
||||
/*
|
||||
collect the mse values that are within 5% of the best values
|
||||
optimize each one and choose the best
|
||||
*/
|
||||
// hack for now -- just use the best value WORK
|
||||
for (int i=0; i<NSHAPES && msebest>0.0; ++i)
|
||||
{
|
||||
float mse = roughtwo(t, i, tempendpts);
|
||||
if (mse < msebest)
|
||||
{
|
||||
msebest = mse;
|
||||
shapeindex_best = i;
|
||||
memcpy(endptsbest, tempendpts, sizeof(endptsbest));
|
||||
}
|
||||
|
||||
}
|
||||
return refinetwo(t, shapeindex_best, endptsbest, block);
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
PROJECT(bc7)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
SET(BC7_SRCS
|
||||
avpcl.cpp
|
||||
avpcl.h
|
||||
avpcl_mode0.cpp
|
||||
avpcl_mode1.cpp
|
||||
avpcl_mode2.cpp
|
||||
avpcl_mode3.cpp
|
||||
avpcl_mode4.cpp
|
||||
avpcl_mode5.cpp
|
||||
avpcl_mode6.cpp
|
||||
avpcl_mode7.cpp
|
||||
bits.h
|
||||
endpts.h
|
||||
shapes_three.h
|
||||
shapes_two.h
|
||||
tile.h
|
||||
utils.cpp
|
||||
utils.h)
|
||||
|
||||
ADD_LIBRARY(bc7 STATIC ${BC7_SRCS})
|
||||
|
||||
IF(NOT WIN32)
|
||||
IF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
SET_TARGET_PROPERTIES(bc6h PROPERTIES COMPILE_FLAGS -fPIC)
|
||||
ENDIF(CMAKE_COMPILER_IS_GNUCXX)
|
||||
ENDIF(NOT WIN32)
|
@ -1,264 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// the avpcl compressor and decompressor
|
||||
|
||||
#include "tile.h"
|
||||
#include "avpcl.h"
|
||||
#include "nvcore/Debug.h"
|
||||
#include "nvmath/Vector.inl"
|
||||
#include <cstring>
|
||||
#include <float.h>
|
||||
|
||||
using namespace nv;
|
||||
using namespace AVPCL;
|
||||
|
||||
// global flags
|
||||
bool AVPCL::flag_premult = false;
|
||||
bool AVPCL::flag_nonuniform = false;
|
||||
bool AVPCL::flag_nonuniform_ati = false;
|
||||
|
||||
// global mode
|
||||
bool AVPCL::mode_rgb = false; // true if image had constant alpha = 255
|
||||
|
||||
void AVPCL::compress(const Tile &t, char *block)
|
||||
{
|
||||
char tempblock[AVPCL::BLOCKSIZE];
|
||||
float msebest = FLT_MAX;
|
||||
|
||||
float mse_mode0 = AVPCL::compress_mode0(t, tempblock); if(mse_mode0 < msebest) { msebest = mse_mode0; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode1 = AVPCL::compress_mode1(t, tempblock); if(mse_mode1 < msebest) { msebest = mse_mode1; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode2 = AVPCL::compress_mode2(t, tempblock); if(mse_mode2 < msebest) { msebest = mse_mode2; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode3 = AVPCL::compress_mode3(t, tempblock); if(mse_mode3 < msebest) { msebest = mse_mode3; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode4 = AVPCL::compress_mode4(t, tempblock); if(mse_mode4 < msebest) { msebest = mse_mode4; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode5 = AVPCL::compress_mode5(t, tempblock); if(mse_mode5 < msebest) { msebest = mse_mode5; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode6 = AVPCL::compress_mode6(t, tempblock); if(mse_mode6 < msebest) { msebest = mse_mode6; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
float mse_mode7 = AVPCL::compress_mode7(t, tempblock); if(mse_mode7 < msebest) { msebest = mse_mode7; memcpy(block, tempblock, AVPCL::BLOCKSIZE); }
|
||||
|
||||
/*if (errfile)
|
||||
{
|
||||
float errs[21];
|
||||
int nerrs = 8;
|
||||
errs[0] = mse_mode0;
|
||||
errs[1] = mse_mode1;
|
||||
errs[2] = mse_mode2;
|
||||
errs[3] = mse_mode3;
|
||||
errs[4] = mse_mode4;
|
||||
errs[5] = mse_mode5;
|
||||
errs[6] = mse_mode6;
|
||||
errs[7] = mse_mode7;
|
||||
if (fwrite(errs, sizeof(float), nerrs, errfile) != nerrs)
|
||||
throw "Write error on error file";
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
static int getbit(char *b, int start)
|
||||
{
|
||||
if (start < 0 || start >= 128) return 0; // out of range
|
||||
|
||||
int ix = start >> 3;
|
||||
return (b[ix] & (1 << (start & 7))) != 0;
|
||||
}
|
||||
|
||||
static int getbits(char *b, int start, int len)
|
||||
{
|
||||
int out = 0;
|
||||
for (int i=0; i<len; ++i)
|
||||
out |= getbit(b, start+i) << i;
|
||||
return out;
|
||||
}
|
||||
|
||||
static void setbit(char *b, int start, int bit)
|
||||
{
|
||||
if (start < 0 || start >= 128) return; // out of range
|
||||
|
||||
int ix = start >> 3;
|
||||
|
||||
if (bit & 1)
|
||||
b[ix] |= (1 << (start & 7));
|
||||
else
|
||||
b[ix] &= ~(1 << (start & 7));
|
||||
}
|
||||
|
||||
static void setbits(char *b, int start, int len, int bits)
|
||||
{
|
||||
for (int i=0; i<len; ++i)
|
||||
setbit(b, start+i, bits >> i);
|
||||
}
|
||||
*/
|
||||
|
||||
void AVPCL::decompress(const char *cblock, Tile &t)
|
||||
{
|
||||
char block[AVPCL::BLOCKSIZE];
|
||||
memcpy(block, cblock, AVPCL::BLOCKSIZE);
|
||||
|
||||
switch(getmode(block))
|
||||
{
|
||||
case 0: AVPCL::decompress_mode0(block, t); break;
|
||||
case 1: AVPCL::decompress_mode1(block, t); break;
|
||||
case 2: AVPCL::decompress_mode2(block, t); break;
|
||||
case 3: AVPCL::decompress_mode3(block, t); break;
|
||||
case 4: AVPCL::decompress_mode4(block, t); break;
|
||||
case 5: AVPCL::decompress_mode5(block, t); break;
|
||||
case 6: AVPCL::decompress_mode6(block, t); break;
|
||||
case 7: AVPCL::decompress_mode7(block, t); break;
|
||||
case 8: // return a black tile if you get a reserved mode
|
||||
for (int y=0; y<Tile::TILE_H; ++y)
|
||||
for (int x=0; x<Tile::TILE_W; ++x)
|
||||
t.data[y][x].set(0, 0, 0, 0);
|
||||
break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void AVPCL::compress(string inf, string avpclf, string errf)
|
||||
{
|
||||
Array2D<RGBA> pixels;
|
||||
int w, h;
|
||||
char block[AVPCL::BLOCKSIZE];
|
||||
|
||||
Targa::read(inf, pixels, w, h);
|
||||
FILE *avpclfile = fopen(avpclf.c_str(), "wb");
|
||||
if (avpclfile == NULL) throw "Unable to open .avpcl file for write";
|
||||
FILE *errfile = NULL;
|
||||
if (errf != "")
|
||||
{
|
||||
errfile = fopen(errf.c_str(), "wb");
|
||||
if (errfile == NULL) throw "Unable to open error file for write";
|
||||
}
|
||||
|
||||
// Look at alpha channel and override the premult flag if alpha is constant (but only if premult is set)
|
||||
if (AVPCL::flag_premult)
|
||||
{
|
||||
if (AVPCL::mode_rgb)
|
||||
{
|
||||
AVPCL::flag_premult = false;
|
||||
cout << endl << "NOTE: Source image alpha is constant 255, turning off premultiplied-alpha error metric." << endl << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// stuff for progress bar O.o
|
||||
int ntiles = ((h+Tile::TILE_H-1)/Tile::TILE_H)*((w+Tile::TILE_W-1)/Tile::TILE_W);
|
||||
int tilecnt = 0;
|
||||
clock_t start, prev, cur;
|
||||
|
||||
start = prev = clock();
|
||||
|
||||
// convert to tiles and compress each tile
|
||||
for (int y=0; y<h; y+=Tile::TILE_H)
|
||||
{
|
||||
int ysize = min(Tile::TILE_H, h-y);
|
||||
for (int x=0; x<w; x+=Tile::TILE_W)
|
||||
{
|
||||
if ((tilecnt%100) == 0) { cur = clock(); printf("Progress %d of %d, %5.2f seconds per 100 tiles\r", tilecnt, ntiles, float(cur-prev)/CLOCKS_PER_SEC); fflush(stdout); prev = cur; }
|
||||
|
||||
int xsize = min(Tile::TILE_W, w-x);
|
||||
Tile t(xsize, ysize);
|
||||
|
||||
t.insert(pixels, x, y);
|
||||
|
||||
AVPCL::compress(t, block, errfile);
|
||||
if (fwrite(block, sizeof(char), AVPCL::BLOCKSIZE, avpclfile) != AVPCL::BLOCKSIZE)
|
||||
throw "File error on write";
|
||||
|
||||
// progress bar
|
||||
++tilecnt;
|
||||
}
|
||||
}
|
||||
|
||||
cur = clock();
|
||||
printf("\nTotal time to compress: %.2f seconds\n\n", float(cur-start)/CLOCKS_PER_SEC); // advance to next line finally
|
||||
|
||||
if (fclose(avpclfile)) throw "Close failed on .avpcl file";
|
||||
if (errfile && fclose(errfile)) throw "Close failed on error file";
|
||||
}
|
||||
|
||||
static int str2int(std::string s)
|
||||
{
|
||||
int thing;
|
||||
std::stringstream str (stringstream::in | stringstream::out);
|
||||
str << s;
|
||||
str >> thing;
|
||||
return thing;
|
||||
}
|
||||
|
||||
// avpcl file name is ...-w-h-RGB[A].avpcl, extract width and height
|
||||
static void extract(string avpclf, int &w, int &h, bool &mode_rgb)
|
||||
{
|
||||
size_t n = avpclf.rfind('.', avpclf.length()-1);
|
||||
size_t n1 = avpclf.rfind('-', n-1);
|
||||
size_t n2 = avpclf.rfind('-', n1-1);
|
||||
size_t n3 = avpclf.rfind('-', n2-1);
|
||||
// ...-wwww-hhhh-RGB[A].avpcl
|
||||
// ^ ^ ^ ^
|
||||
// n3 n2 n1 n n3<n2<n1<n
|
||||
string width = avpclf.substr(n3+1, n2-n3-1);
|
||||
w = str2int(width);
|
||||
string height = avpclf.substr(n2+1, n1-n2-1);
|
||||
h = str2int(height);
|
||||
string mode = avpclf.substr(n1+1, n-n1-1);
|
||||
mode_rgb = mode == "RGB";
|
||||
}
|
||||
|
||||
static int modehist[8];
|
||||
|
||||
static void stats(char block[AVPCL::BLOCKSIZE])
|
||||
{
|
||||
int m = AVPCL::getmode(block);
|
||||
modehist[m]++;
|
||||
}
|
||||
|
||||
static void printstats()
|
||||
{
|
||||
printf("\nMode histogram: "); for (int i=0; i<8; ++i) { printf("%d,", modehist[i]); }
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void AVPCL::decompress(string avpclf, string outf)
|
||||
{
|
||||
Array2D<RGBA> pixels;
|
||||
int w, h;
|
||||
char block[AVPCL::BLOCKSIZE];
|
||||
|
||||
extract(avpclf, w, h, AVPCL::mode_rgb);
|
||||
FILE *avpclfile = fopen(avpclf.c_str(), "rb");
|
||||
if (avpclfile == NULL) throw "Unable to open .avpcl file for read";
|
||||
pixels.resizeErase(h, w);
|
||||
|
||||
// convert to tiles and decompress each tile
|
||||
for (int y=0; y<h; y+=Tile::TILE_H)
|
||||
{
|
||||
int ysize = min(Tile::TILE_H, h-y);
|
||||
for (int x=0; x<w; x+=Tile::TILE_W)
|
||||
{
|
||||
int xsize = min(Tile::TILE_W, w-x);
|
||||
Tile t(xsize, ysize);
|
||||
|
||||
if (fread(block, sizeof(char), AVPCL::BLOCKSIZE, avpclfile) != AVPCL::BLOCKSIZE)
|
||||
throw "File error on read";
|
||||
|
||||
stats(block); // collect statistics
|
||||
|
||||
AVPCL::decompress(block, t);
|
||||
|
||||
t.extract(pixels, x, y);
|
||||
}
|
||||
}
|
||||
if (fclose(avpclfile)) throw "Close failed on .avpcl file";
|
||||
|
||||
Targa::write(outf, pixels, w, h);
|
||||
|
||||
printstats(); // print statistics
|
||||
}
|
||||
*/
|
@ -1,99 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_H
|
||||
#define _AVPCL_H
|
||||
|
||||
#include "tile.h"
|
||||
#include "bits.h"
|
||||
|
||||
#define DISABLE_EXHAUSTIVE 1 // define this if you don't want to spend a lot of time on exhaustive compression
|
||||
#define USE_ZOH_INTERP 1 // use zoh interpolator, otherwise use exact avpcl interpolators
|
||||
#define USE_ZOH_INTERP_ROUNDED 1 // use the rounded versions!
|
||||
|
||||
namespace AVPCL {
|
||||
|
||||
static const int NREGIONS_TWO = 2;
|
||||
static const int NREGIONS_THREE = 3;
|
||||
|
||||
static const int BLOCKSIZE=16;
|
||||
static const int BITSIZE=128;
|
||||
|
||||
// global flags
|
||||
extern bool flag_premult;
|
||||
extern bool flag_nonuniform;
|
||||
extern bool flag_nonuniform_ati;
|
||||
|
||||
// global mode
|
||||
extern bool mode_rgb; // true if image had constant alpha = 255
|
||||
|
||||
void compress(const Tile &t, char *block);
|
||||
void decompress(const char *block, Tile &t);
|
||||
|
||||
float compress_mode0(const Tile &t, char *block);
|
||||
void decompress_mode0(const char *block, Tile &t);
|
||||
|
||||
float compress_mode1(const Tile &t, char *block);
|
||||
void decompress_mode1(const char *block, Tile &t);
|
||||
|
||||
float compress_mode2(const Tile &t, char *block);
|
||||
void decompress_mode2(const char *block, Tile &t);
|
||||
|
||||
float compress_mode3(const Tile &t, char *block);
|
||||
void decompress_mode3(const char *block, Tile &t);
|
||||
|
||||
float compress_mode4(const Tile &t, char *block);
|
||||
void decompress_mode4(const char *block, Tile &t);
|
||||
|
||||
float compress_mode5(const Tile &t, char *block);
|
||||
void decompress_mode5(const char *block, Tile &t);
|
||||
|
||||
float compress_mode6(const Tile &t, char *block);
|
||||
void decompress_mode6(const char *block, Tile &t);
|
||||
|
||||
float compress_mode7(const Tile &t, char *block);
|
||||
void decompress_mode7(const char *block, Tile &t);
|
||||
|
||||
inline int getmode(Bits &in)
|
||||
{
|
||||
int mode = 0;
|
||||
|
||||
if (in.read(1)) mode = 0;
|
||||
else if (in.read(1)) mode = 1;
|
||||
else if (in.read(1)) mode = 2;
|
||||
else if (in.read(1)) mode = 3;
|
||||
else if (in.read(1)) mode = 4;
|
||||
else if (in.read(1)) mode = 5;
|
||||
else if (in.read(1)) mode = 6;
|
||||
else if (in.read(1)) mode = 7;
|
||||
else mode = 8; // reserved
|
||||
return mode;
|
||||
}
|
||||
inline int getmode(const char *block)
|
||||
{
|
||||
int bits = block[0], mode = 0;
|
||||
|
||||
if (bits & 1) mode = 0;
|
||||
else if ((bits&3) == 2) mode = 1;
|
||||
else if ((bits&7) == 4) mode = 2;
|
||||
else if ((bits & 0xF) == 8) mode = 3;
|
||||
else if ((bits & 0x1F) == 16) mode = 4;
|
||||
else if ((bits & 0x3F) == 32) mode = 5;
|
||||
else if ((bits & 0x7F) == 64) mode = 6;
|
||||
else if ((bits & 0xFF) == 128) mode = 7;
|
||||
else mode = 8; // reserved
|
||||
return mode;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,390 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// Utility and common routines
|
||||
|
||||
#include "avpcl_utils.h"
|
||||
#include "avpcl.h"
|
||||
#include "nvcore/Debug.h"
|
||||
#include "nvmath/Vector.inl"
|
||||
#include <math.h>
|
||||
|
||||
using namespace nv;
|
||||
using namespace AVPCL;
|
||||
|
||||
static const int denom7_weights[] = {0, 9, 18, 27, 37, 46, 55, 64}; // divided by 64
|
||||
static const int denom15_weights[] = {0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64}; // divided by 64
|
||||
|
||||
int Utils::lerp(int a, int b, int i, int bias, int denom)
|
||||
{
|
||||
#ifdef USE_ZOH_INTERP
|
||||
nvAssert (denom == 3 || denom == 7 || denom == 15);
|
||||
nvAssert (i >= 0 && i <= denom);
|
||||
nvAssert (bias >= 0 && bias <= denom/2);
|
||||
nvAssert (a >= 0 && b >= 0);
|
||||
|
||||
int round = 0;
|
||||
#ifdef USE_ZOH_INTERP_ROUNDED
|
||||
round = 32;
|
||||
#endif
|
||||
|
||||
switch (denom)
|
||||
{
|
||||
case 3: denom *= 5; i *= 5; // fall through to case 15
|
||||
case 15:return (a*denom15_weights[denom-i] + b*denom15_weights[i] + round) >> 6;
|
||||
case 7: return (a*denom7_weights[denom-i] + b*denom7_weights[i] + round) >> 6;
|
||||
default: nvUnreachable(); return 0;
|
||||
}
|
||||
#else
|
||||
return (((a)*((denom)-i)+(b)*(i)+(bias))/(denom)); // simple exact interpolation
|
||||
#endif
|
||||
}
|
||||
|
||||
Vector4 Utils::lerp(Vector4::Arg a, Vector4::Arg b, int i, int bias, int denom)
|
||||
{
|
||||
#ifdef USE_ZOH_INTERP
|
||||
nvAssert (denom == 3 || denom == 7 || denom == 15);
|
||||
nvAssert (i >= 0 && i <= denom);
|
||||
nvAssert (bias >= 0 && bias <= denom/2);
|
||||
// nvAssert (a >= 0 && b >= 0);
|
||||
|
||||
// no need to bias these as this is an exact division
|
||||
|
||||
switch (denom)
|
||||
{
|
||||
case 3: denom *= 5; i *= 5; // fall through to case 15
|
||||
case 15:return (a*float(denom15_weights[denom-i]) + b*float(denom15_weights[i])) / 64.0f;
|
||||
case 7: return (a*float(denom7_weights[denom-i]) + b*float(denom7_weights[i])) / 64.0f;
|
||||
default: nvUnreachable(); return Vector4(0);
|
||||
}
|
||||
#else
|
||||
return (((a)*((denom)-i)+(b)*(i)+(bias))/(denom)); // simple exact interpolation
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
int Utils::unquantize(int q, int prec)
|
||||
{
|
||||
int unq;
|
||||
|
||||
nvAssert (prec > 3); // we only want to do one replicate
|
||||
|
||||
#ifdef USE_ZOH_QUANT
|
||||
if (prec >= 8)
|
||||
unq = q;
|
||||
else if (q == 0)
|
||||
unq = 0;
|
||||
else if (q == ((1<<prec)-1))
|
||||
unq = 255;
|
||||
else
|
||||
unq = (q * 256 + 128) >> prec;
|
||||
#else
|
||||
// avpcl unquantizer -- bit replicate
|
||||
unq = (q << (8-prec)) | (q >> (2*prec-8));
|
||||
#endif
|
||||
|
||||
return unq;
|
||||
}
|
||||
|
||||
// quantize to the best value -- i.e., minimize unquantize error
|
||||
int Utils::quantize(float value, int prec)
|
||||
{
|
||||
int q, unq;
|
||||
|
||||
nvAssert (prec > 3); // we only want to do one replicate
|
||||
|
||||
unq = (int)floor(value + 0.5f);
|
||||
nvAssert (unq <= 255);
|
||||
|
||||
#ifdef USE_ZOH_QUANT
|
||||
q = (prec >= 8) ? unq : (unq << prec) / 256;
|
||||
#else
|
||||
// avpcl quantizer -- scale properly for best possible bit-replicated result
|
||||
q = (unq * ((1<<prec)-1) + 127)/255;
|
||||
#endif
|
||||
|
||||
nvAssert (q >= 0 && q < (1 << prec));
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
float Utils::metric4(Vector4::Arg a, Vector4::Arg b)
|
||||
{
|
||||
Vector4 err = a - b;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else /*if (AVPCL::flag_nonuniform_ati)*/
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err.x *= rwt;
|
||||
err.y *= gwt;
|
||||
err.z *= bwt;
|
||||
}
|
||||
|
||||
return lengthSquared(err);
|
||||
}
|
||||
|
||||
// WORK -- implement rotatemode for the below -- that changes where the rwt, gwt, and bwt's go.
|
||||
float Utils::metric3(Vector3::Arg a, Vector3::Arg b, int rotatemode)
|
||||
{
|
||||
Vector3 err = a - b;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else if (AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// adjust weights based on rotatemode
|
||||
switch(rotatemode)
|
||||
{
|
||||
case ROTATEMODE_RGBA_RGBA: break;
|
||||
case ROTATEMODE_RGBA_AGBR: rwt = 1.0f; break;
|
||||
case ROTATEMODE_RGBA_RABG: gwt = 1.0f; break;
|
||||
case ROTATEMODE_RGBA_RGAB: bwt = 1.0f; break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err.x *= rwt;
|
||||
err.y *= gwt;
|
||||
err.z *= bwt;
|
||||
}
|
||||
|
||||
return lengthSquared(err);
|
||||
}
|
||||
|
||||
float Utils::metric1(const float a, const float b, int rotatemode)
|
||||
{
|
||||
float err = a - b;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt, awt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else if (AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// adjust weights based on rotatemode
|
||||
switch(rotatemode)
|
||||
{
|
||||
case ROTATEMODE_RGBA_RGBA: awt = 1.0f; break;
|
||||
case ROTATEMODE_RGBA_AGBR: awt = rwt; break;
|
||||
case ROTATEMODE_RGBA_RABG: awt = gwt; break;
|
||||
case ROTATEMODE_RGBA_RGAB: awt = bwt; break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err *= awt;
|
||||
}
|
||||
|
||||
return err * err;
|
||||
}
|
||||
|
||||
float Utils::premult(float r, float a)
|
||||
{
|
||||
// note that the args are really integers stored in floats
|
||||
int R = int(r), A = int(a);
|
||||
|
||||
nvAssert ((R==r) && (A==a));
|
||||
|
||||
return float((R*A + 127)/255);
|
||||
}
|
||||
|
||||
static void premult4(Vector4& rgba)
|
||||
{
|
||||
rgba.x = Utils::premult(rgba.x, rgba.w);
|
||||
rgba.y = Utils::premult(rgba.y, rgba.w);
|
||||
rgba.z = Utils::premult(rgba.z, rgba.w);
|
||||
}
|
||||
|
||||
static void premult3(Vector3& rgb, float a)
|
||||
{
|
||||
rgb.x = Utils::premult(rgb.x, a);
|
||||
rgb.y = Utils::premult(rgb.y, a);
|
||||
rgb.z = Utils::premult(rgb.z, a);
|
||||
}
|
||||
|
||||
float Utils::metric4premult(Vector4::Arg a, Vector4::Arg b)
|
||||
{
|
||||
Vector4 pma = a, pmb = b;
|
||||
|
||||
premult4(pma);
|
||||
premult4(pmb);
|
||||
|
||||
Vector4 err = pma - pmb;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else /*if (AVPCL::flag_nonuniform_ati)*/
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err.x *= rwt;
|
||||
err.y *= gwt;
|
||||
err.z *= bwt;
|
||||
}
|
||||
|
||||
return lengthSquared(err);
|
||||
}
|
||||
|
||||
float Utils::metric3premult_alphaout(Vector3::Arg rgb0, float a0, Vector3::Arg rgb1, float a1)
|
||||
{
|
||||
Vector3 pma = rgb0, pmb = rgb1;
|
||||
|
||||
premult3(pma, a0);
|
||||
premult3(pmb, a1);
|
||||
|
||||
Vector3 err = pma - pmb;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else /*if (AVPCL::flag_nonuniform_ati)*/
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err.x *= rwt;
|
||||
err.y *= gwt;
|
||||
err.z *= bwt;
|
||||
}
|
||||
|
||||
return lengthSquared(err);
|
||||
}
|
||||
|
||||
float Utils::metric3premult_alphain(Vector3::Arg rgb0, Vector3::Arg rgb1, int rotatemode)
|
||||
{
|
||||
Vector3 pma = rgb0, pmb = rgb1;
|
||||
|
||||
switch(rotatemode)
|
||||
{
|
||||
case ROTATEMODE_RGBA_RGBA:
|
||||
// this function isn't supposed to be called for this rotatemode
|
||||
nvUnreachable();
|
||||
break;
|
||||
case ROTATEMODE_RGBA_AGBR:
|
||||
pma.y = premult(pma.y, pma.x);
|
||||
pma.z = premult(pma.z, pma.x);
|
||||
pmb.y = premult(pmb.y, pmb.x);
|
||||
pmb.z = premult(pmb.z, pmb.x);
|
||||
break;
|
||||
case ROTATEMODE_RGBA_RABG:
|
||||
pma.x = premult(pma.x, pma.y);
|
||||
pma.z = premult(pma.z, pma.y);
|
||||
pmb.x = premult(pmb.x, pmb.y);
|
||||
pmb.z = premult(pmb.z, pmb.y);
|
||||
break;
|
||||
case ROTATEMODE_RGBA_RGAB:
|
||||
pma.x = premult(pma.x, pma.z);
|
||||
pma.y = premult(pma.y, pma.z);
|
||||
pmb.x = premult(pmb.x, pmb.z);
|
||||
pmb.y = premult(pmb.y, pmb.z);
|
||||
break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
|
||||
Vector3 err = pma - pmb;
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else /*if (AVPCL::flag_nonuniform_ati)*/
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err.x *= rwt;
|
||||
err.y *= gwt;
|
||||
err.z *= bwt;
|
||||
}
|
||||
|
||||
return lengthSquared(err);
|
||||
}
|
||||
|
||||
float Utils::metric1premult(float rgb0, float a0, float rgb1, float a1, int rotatemode)
|
||||
{
|
||||
float err = premult(rgb0, a0) - premult(rgb1, a1);
|
||||
|
||||
// if nonuniform, select weights and weigh away
|
||||
if (AVPCL::flag_nonuniform || AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
float rwt, gwt, bwt, awt;
|
||||
if (AVPCL::flag_nonuniform)
|
||||
{
|
||||
rwt = 0.299f; gwt = 0.587f; bwt = 0.114f;
|
||||
}
|
||||
else if (AVPCL::flag_nonuniform_ati)
|
||||
{
|
||||
rwt = 0.3086f; gwt = 0.6094f; bwt = 0.0820f;
|
||||
}
|
||||
|
||||
// adjust weights based on rotatemode
|
||||
switch(rotatemode)
|
||||
{
|
||||
case ROTATEMODE_RGBA_RGBA: awt = 1.0f; break;
|
||||
case ROTATEMODE_RGBA_AGBR: awt = rwt; break;
|
||||
case ROTATEMODE_RGBA_RABG: awt = gwt; break;
|
||||
case ROTATEMODE_RGBA_RGAB: awt = bwt; break;
|
||||
default: nvUnreachable();
|
||||
}
|
||||
|
||||
// weigh the components
|
||||
err *= awt;
|
||||
}
|
||||
|
||||
return err * err;
|
||||
}
|
@ -1,61 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
// utility class holding common routines
|
||||
#ifndef _AVPCL_UTILS_H
|
||||
#define _AVPCL_UTILS_H
|
||||
|
||||
#include "nvmath/Vector.h"
|
||||
|
||||
namespace AVPCL {
|
||||
|
||||
inline int SIGN_EXTEND(int x, int nb) { return ((((x)&(1<<((nb)-1)))?((~0)<<(nb)):0)|(x)); }
|
||||
|
||||
static const int INDEXMODE_BITS = 1; // 2 different index modes
|
||||
static const int NINDEXMODES = (1<<(INDEXMODE_BITS));
|
||||
static const int INDEXMODE_ALPHA_IS_3BITS = 0;
|
||||
static const int INDEXMODE_ALPHA_IS_2BITS = 1;
|
||||
|
||||
static const int ROTATEMODE_BITS = 2; // 4 different rotate modes
|
||||
static const int NROTATEMODES = (1<<(ROTATEMODE_BITS));
|
||||
static const int ROTATEMODE_RGBA_RGBA = 0;
|
||||
static const int ROTATEMODE_RGBA_AGBR = 1;
|
||||
static const int ROTATEMODE_RGBA_RABG = 2;
|
||||
static const int ROTATEMODE_RGBA_RGAB = 3;
|
||||
|
||||
class Utils
|
||||
{
|
||||
public:
|
||||
// error metrics
|
||||
static float metric4(nv::Vector4::Arg a, nv::Vector4::Arg b);
|
||||
static float metric3(nv::Vector3::Arg a, nv::Vector3::Arg b, int rotatemode);
|
||||
static float metric1(float a, float b, int rotatemode);
|
||||
|
||||
static float metric4premult(nv::Vector4::Arg rgba0, nv::Vector4::Arg rgba1);
|
||||
static float metric3premult_alphaout(nv::Vector3::Arg rgb0, float a0, nv::Vector3::Arg rgb1, float a1);
|
||||
static float metric3premult_alphain(nv::Vector3::Arg rgb0, nv::Vector3::Arg rgb1, int rotatemode);
|
||||
static float metric1premult(float rgb0, float a0, float rgb1, float a1, int rotatemode);
|
||||
|
||||
static float premult(float r, float a);
|
||||
|
||||
// quantization and unquantization
|
||||
static int unquantize(int q, int prec);
|
||||
static int quantize(float value, int prec);
|
||||
|
||||
// lerping
|
||||
static int lerp(int a, int b, int i, int bias, int denom);
|
||||
static nv::Vector4 lerp(nv::Vector4::Arg a, nv::Vector4::Arg b, int i, int bias, int denom);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_BITS_H
|
||||
#define _AVPCL_BITS_H
|
||||
|
||||
// read/write a bitstream
|
||||
|
||||
#include "nvcore/Debug.h"
|
||||
|
||||
namespace AVPCL {
|
||||
|
||||
class Bits
|
||||
{
|
||||
public:
|
||||
|
||||
Bits(char *data, int maxdatabits) { nvAssert (data && maxdatabits > 0); bptr = bend = 0; bits = data; maxbits = maxdatabits; readonly = 0;}
|
||||
Bits(const char *data, int availdatabits) { nvAssert (data && availdatabits > 0); bptr = 0; bend = availdatabits; cbits = data; maxbits = availdatabits; readonly = 1;}
|
||||
|
||||
void write(int value, int nbits) {
|
||||
nvAssert (nbits >= 0 && nbits < 32);
|
||||
nvAssert (sizeof(int)>= 4);
|
||||
for (int i=0; i<nbits; ++i)
|
||||
writeone(value>>i);
|
||||
}
|
||||
int read(int nbits) {
|
||||
nvAssert (nbits >= 0 && nbits < 32);
|
||||
nvAssert (sizeof(int)>= 4);
|
||||
int out = 0;
|
||||
for (int i=0; i<nbits; ++i)
|
||||
out |= readone() << i;
|
||||
return out;
|
||||
}
|
||||
int getptr() { return bptr; }
|
||||
void setptr(int ptr) { nvAssert (ptr >= 0 && ptr < maxbits); bptr = ptr; }
|
||||
int getsize() { return bend; }
|
||||
|
||||
private:
|
||||
int bptr; // next bit to read
|
||||
int bend; // last written bit + 1
|
||||
char *bits; // ptr to user bit stream
|
||||
const char *cbits; // ptr to const user bit stream
|
||||
int maxbits; // max size of user bit stream
|
||||
char readonly; // 1 if this is a read-only stream
|
||||
|
||||
int readone() {
|
||||
nvAssert (bptr < bend);
|
||||
if (bptr >= bend) return 0;
|
||||
int bit = (readonly ? cbits[bptr>>3] : bits[bptr>>3]) & (1 << (bptr & 7));
|
||||
++bptr;
|
||||
return bit != 0;
|
||||
}
|
||||
void writeone(int bit) {
|
||||
nvAssert (!readonly); // "Writing a read-only bit stream"
|
||||
nvAssert (bptr < maxbits);
|
||||
if (bptr >= maxbits) return;
|
||||
if (bit&1)
|
||||
bits[bptr>>3] |= 1 << (bptr & 7);
|
||||
else
|
||||
bits[bptr>>3] &= ~(1 << (bptr & 7));
|
||||
if (bptr++ >= bend) bend = bptr;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,81 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_ENDPTS_H
|
||||
#define _AVPCL_ENDPTS_H
|
||||
|
||||
// endpoint definitions and routines to search through endpoint space
|
||||
|
||||
#include "nvmath/Vector.h"
|
||||
|
||||
namespace AVPCL {
|
||||
|
||||
static const int NCHANNELS_RGB = 3;
|
||||
static const int NCHANNELS_RGBA = 4;
|
||||
static const int CHANNEL_R = 0;
|
||||
static const int CHANNEL_G = 1;
|
||||
static const int CHANNEL_B = 2;
|
||||
static const int CHANNEL_A = 3;
|
||||
|
||||
struct FltEndpts
|
||||
{
|
||||
nv::Vector4 A;
|
||||
nv::Vector4 B;
|
||||
};
|
||||
|
||||
struct IntEndptsRGB
|
||||
{
|
||||
int A[NCHANNELS_RGB];
|
||||
int B[NCHANNELS_RGB];
|
||||
};
|
||||
|
||||
struct IntEndptsRGB_1
|
||||
{
|
||||
int A[NCHANNELS_RGB];
|
||||
int B[NCHANNELS_RGB];
|
||||
int lsb; // shared lsb for A and B
|
||||
};
|
||||
|
||||
struct IntEndptsRGB_2
|
||||
{
|
||||
int A[NCHANNELS_RGB];
|
||||
int B[NCHANNELS_RGB];
|
||||
int a_lsb; // lsb for A
|
||||
int b_lsb; // lsb for B
|
||||
};
|
||||
|
||||
|
||||
struct IntEndptsRGBA
|
||||
{
|
||||
int A[NCHANNELS_RGBA];
|
||||
int B[NCHANNELS_RGBA];
|
||||
};
|
||||
|
||||
struct IntEndptsRGBA_2
|
||||
{
|
||||
int A[NCHANNELS_RGBA];
|
||||
int B[NCHANNELS_RGBA];
|
||||
int a_lsb; // lsb for A
|
||||
int b_lsb; // lsb for B
|
||||
};
|
||||
|
||||
struct IntEndptsRGBA_2a
|
||||
{
|
||||
int A[NCHANNELS_RGBA];
|
||||
int B[NCHANNELS_RGBA];
|
||||
int a_lsb; // lsb for RGB channels of A
|
||||
int b_lsb; // lsb for RGB channels of A
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -1,132 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_SHAPES_THREE_H
|
||||
#define _AVPCL_SHAPES_THREE_H
|
||||
|
||||
// shapes for 3 regions
|
||||
|
||||
#define NREGIONS 3
|
||||
#define NSHAPES 64
|
||||
#define SHAPEBITS 6
|
||||
|
||||
static int shapes[NSHAPES*16] =
|
||||
{
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 2, 2,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 2, 0, 0, 1, 0, 0, 2, 2,
|
||||
0, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1, 1, 0, 0, 1, 1,
|
||||
2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 2, 2, 0, 0, 1, 1,
|
||||
1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
|
||||
1, 1, 2, 2, 0, 0, 2, 2, 1, 1, 1, 1, 2, 2, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 2,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 0, 0, 1, 2,
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 1, 2,
|
||||
|
||||
0, 1, 1, 2, 0, 1, 2, 2, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 2, 0, 1, 2, 2, 0, 1, 1, 2, 2, 0, 0, 1,
|
||||
0, 1, 1, 2, 0, 1, 2, 2, 1, 1, 2, 2, 2, 2, 0, 0,
|
||||
0, 1, 1, 2, 0, 1, 2, 2, 1, 2, 2, 2, 2, 2, 2, 0,
|
||||
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 2, 2,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 2, 2, 0, 0, 2, 2,
|
||||
0, 1, 1, 2, 2, 0, 0, 1, 1, 1, 2, 2, 0, 0, 2, 2,
|
||||
1, 1, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, 1, 1, 1, 1,
|
||||
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0,
|
||||
0, 2, 2, 2, 2, 2, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0,
|
||||
0, 2, 2, 2, 2, 2, 2, 1, 0, 1, 2, 2, 2, 2, 1, 0,
|
||||
|
||||
0, 1, 2, 2, 0, 0, 1, 2, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 2, 2, 0, 0, 1, 2, 1, 2, 2, 1, 0, 1, 1, 0,
|
||||
0, 0, 1, 1, 1, 1, 2, 2, 1, 2, 2, 1, 1, 2, 2, 1,
|
||||
0, 0, 0, 0, 2, 2, 2, 2, 0, 1, 1, 0, 1, 2, 2, 1,
|
||||
|
||||
0, 0, 2, 2, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 0, 2, 0, 1, 1, 0, 0, 1, 2, 2, 2, 0, 0, 0,
|
||||
1, 1, 0, 2, 2, 0, 0, 2, 0, 1, 2, 2, 2, 2, 1, 1,
|
||||
0, 0, 2, 2, 2, 2, 2, 2, 0, 0, 1, 1, 2, 2, 2, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 2, 2, 2, 0, 0, 1, 1, 0, 1, 2, 0,
|
||||
0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 1, 2, 0, 1, 2, 0,
|
||||
1, 1, 2, 2, 0, 0, 1, 2, 0, 0, 2, 2, 0, 1, 2, 0,
|
||||
1, 2, 2, 2, 0, 0, 1, 1, 0, 2, 2, 2, 0, 1, 2, 0,
|
||||
|
||||
0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 1, 1, 2, 0, 1, 2, 0, 1, 2, 2, 2, 0, 0,
|
||||
2, 2, 2, 2, 2, 0, 1, 2, 1, 2, 0, 1, 1, 1, 2, 2,
|
||||
0, 0, 0, 0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 0, 1, 1,
|
||||
|
||||
0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 2, 2,
|
||||
1, 1, 2, 2, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 2, 2,
|
||||
2, 2, 0, 0, 2, 2, 2, 2, 2, 1, 2, 1, 0, 0, 2, 2,
|
||||
0, 0, 1, 1, 2, 2, 2, 2, 2, 1, 2, 1, 1, 1, 2, 2,
|
||||
|
||||
0, 0, 2, 2, 0, 2, 2, 0, 0, 1, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 1, 1, 1, 2, 2, 1, 2, 2, 2, 2, 2, 1, 2, 1,
|
||||
0, 0, 2, 2, 0, 2, 2, 0, 2, 2, 2, 2, 2, 1, 2, 1,
|
||||
0, 0, 1, 1, 1, 2, 2, 1, 0, 1, 0, 1, 2, 1, 2, 1,
|
||||
|
||||
0, 1, 0, 1, 0, 2, 2, 2, 0, 0, 0, 2, 0, 0, 0, 0,
|
||||
0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
|
||||
0, 1, 0, 1, 0, 2, 2, 2, 0, 0, 0, 2, 2, 1, 1, 2,
|
||||
2, 2, 2, 2, 0, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 2,
|
||||
|
||||
0, 2, 2, 2, 0, 0, 0, 2, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 1, 1, 1, 2, 0, 1, 1, 0, 2, 1, 1, 2,
|
||||
0, 2, 2, 2, 0, 0, 0, 2, 2, 2, 2, 2, 2, 1, 1, 2,
|
||||
|
||||
0, 1, 1, 0, 0, 0, 2, 2, 0, 0, 2, 2, 0, 0, 0, 0,
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 0, 0, 1, 1, 1, 1, 2, 2, 0, 0, 0, 0,
|
||||
2, 2, 2, 2, 0, 0, 2, 2, 0, 0, 2, 2, 2, 1, 1, 2,
|
||||
|
||||
0, 0, 0, 2, 0, 2, 2, 2, 0, 1, 0, 1, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1, 1,
|
||||
0, 0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 1,
|
||||
0, 0, 0, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0,
|
||||
};
|
||||
|
||||
#define REGION(x,y,si) shapes[((si)&3)*4+((si)>>2)*64+(x)+(y)*16]
|
||||
|
||||
static int shapeindex_to_compressed_indices[NSHAPES*3] =
|
||||
{
|
||||
0, 3,15, 0, 3, 8, 0,15, 8, 0,15, 3,
|
||||
0, 8,15, 0, 3,15, 0,15, 3, 0,15, 8,
|
||||
0, 8,15, 0, 8,15, 0, 6,15, 0, 6,15,
|
||||
0, 6,15, 0, 5,15, 0, 3,15, 0, 3, 8,
|
||||
|
||||
0, 3,15, 0, 3, 8, 0, 8,15, 0,15, 3,
|
||||
0, 3,15, 0, 3, 8, 0, 6,15, 0,10, 8,
|
||||
0, 5, 3, 0, 8,15, 0, 8, 6, 0, 6,10,
|
||||
0, 8,15, 0, 5,15, 0,15,10, 0,15, 8,
|
||||
|
||||
0, 8,15, 0,15, 3, 0, 3,15, 0, 5,10,
|
||||
0, 6,10, 0,10, 8, 0, 8, 9, 0,15,10,
|
||||
0,15, 6, 0, 3,15, 0,15, 8, 0, 5,15,
|
||||
0,15, 3, 0,15, 6, 0,15, 6, 0,15, 8,
|
||||
|
||||
0, 3,15, 0,15, 3, 0, 5,15, 0, 5,15,
|
||||
0, 5,15, 0, 8,15, 0, 5,15, 0,10,15,
|
||||
0, 5,15, 0,10,15, 0, 8,15, 0,13,15,
|
||||
0,15, 3, 0,12,15, 0, 3,15, 0, 3, 8
|
||||
|
||||
};
|
||||
#define SHAPEINDEX_TO_COMPRESSED_INDICES(si,region) shapeindex_to_compressed_indices[(si)*3+(region)]
|
||||
|
||||
#endif
|
@ -1,133 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_SHAPES_TWO_H
|
||||
#define _AVPCL_SHAPES_TWO_H
|
||||
|
||||
// shapes for two regions
|
||||
|
||||
#define NREGIONS 2
|
||||
#define NSHAPES 64
|
||||
#define SHAPEBITS 6
|
||||
|
||||
static int shapes[NSHAPES*16] =
|
||||
{
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1,
|
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0,
|
||||
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1,
|
||||
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1,
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1,
|
||||
1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1,
|
||||
1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1,
|
||||
0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
|
||||
0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
|
||||
1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0,
|
||||
0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0,
|
||||
1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1,
|
||||
|
||||
0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1,
|
||||
1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1,
|
||||
1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0,
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0,
|
||||
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1,
|
||||
1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1,
|
||||
1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
|
||||
|
||||
0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0,
|
||||
1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
|
||||
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0,
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1,
|
||||
|
||||
};
|
||||
|
||||
#define REGION(x,y,si) shapes[((si)&3)*4+((si)>>2)*64+(x)+(y)*16]
|
||||
|
||||
static int shapeindex_to_compressed_indices[NSHAPES*2] =
|
||||
{
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
|
||||
0,15, 0, 2, 0, 8, 0, 2,
|
||||
0, 2, 0, 8, 0, 8, 0,15,
|
||||
0, 2, 0, 8, 0, 2, 0, 2,
|
||||
0, 8, 0, 8, 0, 2, 0, 2,
|
||||
|
||||
0,15, 0,15, 0, 6, 0, 8,
|
||||
0, 2, 0, 8, 0,15, 0,15,
|
||||
0, 2, 0, 8, 0, 2, 0, 2,
|
||||
0, 2, 0,15, 0,15, 0, 6,
|
||||
|
||||
0, 6, 0, 2, 0, 6, 0, 8,
|
||||
0,15, 0,15, 0, 2, 0, 2,
|
||||
0,15, 0,15, 0,15, 0,15,
|
||||
0,15, 0, 2, 0, 2, 0,15
|
||||
|
||||
};
|
||||
#define SHAPEINDEX_TO_COMPRESSED_INDICES(si,region) shapeindex_to_compressed_indices[(si)*2+(region)]
|
||||
|
||||
#endif
|
@ -1,41 +0,0 @@
|
||||
/*
|
||||
Copyright 2007 nVidia, Inc.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.
|
||||
|
||||
You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
||||
See the License for the specific language governing permissions and limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _AVPCL_TILE_H
|
||||
#define _AVPCL_TILE_H
|
||||
|
||||
#include "nvmath/Vector.h"
|
||||
#include <math.h>
|
||||
#include "avpcl_utils.h"
|
||||
|
||||
namespace AVPCL {
|
||||
|
||||
// extract a tile of pixels from an array
|
||||
|
||||
class Tile
|
||||
{
|
||||
public:
|
||||
static const int TILE_H = 4;
|
||||
static const int TILE_W = 4;
|
||||
static const int TILE_TOTAL = TILE_H * TILE_W;
|
||||
nv::Vector4 data[TILE_H][TILE_W];
|
||||
float importance_map[TILE_H][TILE_W];
|
||||
int size_x, size_y; // actual size of tile
|
||||
|
||||
Tile() {};
|
||||
~Tile(){};
|
||||
Tile(int xs, int ys) {size_x = xs; size_y = ys;}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -66,8 +66,8 @@ IF(QT4_FOUND)
|
||||
QT4_WRAP_CPP(MOCS compressdialog.h)
|
||||
#QT4_ADD_RESOURCES(RCCS ui/configdialog.rc)
|
||||
|
||||
ADD_EXECUTABLE(nvtt-diag MACOSX_BUNDLE ${SRCS} ${UICS} ${MOCS})
|
||||
TARGET_LINK_LIBRARIES(nvtt-diag ${LIBS})
|
||||
#ADD_EXECUTABLE(nvtt-diag MACOSX_BUNDLE ${SRCS} ${UICS} ${MOCS})
|
||||
#TARGET_LINK_LIBRARIES(nvtt-diag ${LIBS})
|
||||
|
||||
ENDIF(QT4_FOUND)
|
||||
|
||||
|
@ -17,23 +17,6 @@ int main(int argc, char *argv[])
|
||||
CompressDialog::CompressDialog(const QString & fileName, QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
ui.setupUi(this);
|
||||
|
||||
//connect(ui.openButton, SIGNAL(clicked()), this, SLOT(openClicked()));
|
||||
connect(ui.generateMipmapsCheckBox, SIGNAL(stateChanged(int)), this, SLOT(generateMipmapsChanged(int)));
|
||||
connect(ui.mipmapFilterComboBox, SIGNAL(activated(QString)), this, SLOT(mipmapFilterChanged(QString)));
|
||||
//connect(ui.mipmapFilterSettings, SIGNAL(clicked()), this, SLOT(mipmapFilterSettingsShow()));
|
||||
|
||||
connect(ui.formatComboBox, SIGNAL(activated(QString)), this, SLOT(formatChanged(QString)));
|
||||
|
||||
|
||||
connect(ui.redSpinBox, SIGNAL(valueChanged(double)), this, SLOT(colorWeightChanged()));
|
||||
connect(ui.greenSpinBox, SIGNAL(valueChanged(double)), this, SLOT(colorWeightChanged()));
|
||||
connect(ui.blueSpinBox, SIGNAL(valueChanged(double)), this, SLOT(colorWeightChanged()));
|
||||
connect(ui.uniformButton, SIGNAL(toggled(bool)), this, SLOT(uniformWeightToggled(bool)));
|
||||
connect(ui.luminanceButton, SIGNAL(toggled(bool)), this, SLOT(luminanceWeightToggled(bool)));
|
||||
|
||||
//connect(ui.rgbMapRadioButton, SIGNAL(toggled(bool)), this, SLOT(colorModeChanged()));
|
||||
//connect(ui.normalMapRadioButton, SIGNAL(toggled(bool)), this, SLOT(normalMapModeChanged(bool)));
|
||||
}
|
||||
|
||||
CompressDialog::~CompressDialog()
|
||||
@ -46,79 +29,3 @@ void CompressDialog::openClicked()
|
||||
// @@ What is openButton?
|
||||
}
|
||||
|
||||
|
||||
void CompressDialog::generateMipmapsChanged(int state)
|
||||
{
|
||||
Q_UNUSED(state);
|
||||
|
||||
bool generateMipmapEnabled = ui.generateMipmapsCheckBox->isChecked();
|
||||
|
||||
ui.mipmapFilterLabel->setEnabled(generateMipmapEnabled);
|
||||
ui.mipmapFilterComboBox->setEnabled(generateMipmapEnabled);
|
||||
ui.limitMipmapsCheckBox->setEnabled(generateMipmapEnabled);
|
||||
|
||||
bool enableFilterSettings = (ui.mipmapFilterComboBox->currentText() == "Kaiser");
|
||||
ui.mipmapFilterSettings->setEnabled(generateMipmapEnabled && enableFilterSettings);
|
||||
|
||||
bool enableMaxLevel = ui.limitMipmapsCheckBox->isChecked();
|
||||
ui.maxLevelLabel->setEnabled(generateMipmapEnabled && enableMaxLevel);
|
||||
ui.maxLevelSpinBox->setEnabled(generateMipmapEnabled && enableMaxLevel);
|
||||
}
|
||||
|
||||
void CompressDialog::mipmapFilterChanged(QString name)
|
||||
{
|
||||
bool enableFilterSettings = (name == "Kaiser");
|
||||
ui.mipmapFilterSettings->setEnabled(enableFilterSettings);
|
||||
}
|
||||
|
||||
void CompressDialog::formatChanged(QString format)
|
||||
{
|
||||
if (format == "Uncompressed") {
|
||||
ui.formatOptions->setCurrentIndex(1);
|
||||
}
|
||||
else {
|
||||
ui.formatOptions->setCurrentIndex(0);
|
||||
}
|
||||
}
|
||||
|
||||
void CompressDialog::colorWeightChanged()
|
||||
{
|
||||
double r = ui.redSpinBox->value();
|
||||
double g = ui.greenSpinBox->value();
|
||||
double b = ui.blueSpinBox->value();
|
||||
|
||||
bool uniform = (r == 1.0 && g == 1.0 && b == 1.0);
|
||||
bool luminance = (r == 0.3 && g == 0.59 && b == 0.11);
|
||||
|
||||
ui.uniformButton->setChecked(uniform);
|
||||
ui.luminanceButton->setChecked(luminance);
|
||||
}
|
||||
|
||||
void CompressDialog::uniformWeightToggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
{
|
||||
ui.redSpinBox->setValue(1.0);
|
||||
ui.greenSpinBox->setValue(1.0);
|
||||
ui.blueSpinBox->setValue(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
void CompressDialog::luminanceWeightToggled(bool checked)
|
||||
{
|
||||
if (checked)
|
||||
{
|
||||
ui.redSpinBox->setValue(0.3);
|
||||
ui.greenSpinBox->setValue(0.59);
|
||||
ui.blueSpinBox->setValue(0.11);
|
||||
}
|
||||
}
|
||||
|
||||
void CompressDialog::normalMapModeChanged(bool checked)
|
||||
{
|
||||
//ui.alphaModeGroupBox->setEnabled(!checked);
|
||||
//ui.inputGammaSpinBox->setEnabled(!checked);
|
||||
//ui.inputGammaLabel->setEnabled(!checked);
|
||||
//ui.outputGammaSpinBox->setEnabled(!checked);
|
||||
//ui.outputGammaLabel->setEnabled(!checked);
|
||||
}
|
||||
|
@ -16,15 +16,6 @@ public:
|
||||
protected slots:
|
||||
|
||||
void openClicked();
|
||||
void generateMipmapsChanged(int state);
|
||||
void mipmapFilterChanged(QString name);
|
||||
void formatChanged(QString format);
|
||||
|
||||
void colorWeightChanged();
|
||||
void uniformWeightToggled(bool checked);
|
||||
void luminanceWeightToggled(bool checked);
|
||||
|
||||
void normalMapModeChanged(bool checked);
|
||||
|
||||
|
||||
private:
|
||||
|
@ -2,6 +2,14 @@
|
||||
<ui version="4.0">
|
||||
<class>CompressDialog</class>
|
||||
<widget class="QDialog" name="CompressDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>766</width>
|
||||
<height>540</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>280</width>
|
||||
@ -11,12 +19,21 @@
|
||||
<property name="windowTitle">
|
||||
<string>Dialog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="spacing">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
<property name="leftMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>10</number>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
@ -39,694 +56,41 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolBox" name="toolBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Sunken</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>3</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_info">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>249</width>
|
||||
<height>367</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Image Info</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_compression">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>249</width>
|
||||
<height>367</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Compression Options</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Format:</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::NoTextInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="formatComboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Uncompressed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC1 (DXT1)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC1a (DXT1a)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC2 (DXT3)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC3 (DXT5)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC4</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>BC5</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="formatOptions">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_colorweights">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Color Weights</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignHCenter</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="_2">
|
||||
<property name="topMargin">
|
||||
<number>12</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Red</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>redSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="redSpinBox">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Green</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>greenSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="greenSpinBox">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_12">
|
||||
<property name="text">
|
||||
<string>Blue</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>blueSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDoubleSpinBox" name="blueSpinBox">
|
||||
<property name="maximum">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<double>0.050000000000000</double>
|
||||
</property>
|
||||
<property name="value">
|
||||
<double>1.000000000000000</double>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_6">
|
||||
<item>
|
||||
<widget class="QToolButton" name="uniformButton">
|
||||
<property name="text">
|
||||
<string>Uniform</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="luminanceButton">
|
||||
<property name="text">
|
||||
<string>Luminance</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_pixelformat">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>24</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Pixel Format:</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::PlainText</enum>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::NoTextInteraction</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="pixelformatComboBox">
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Custom</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>R8G8B8A8</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>R5G6B5</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>A1</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Color Type:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Fixed</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Float</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Red Bits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="redbitSpinBox">
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Green Bits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="greenbitSpinBox">
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Blue Bits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="bluebitSpinBox">
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Alpha Bits:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="alphabitSpinBox">
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="ditherColorCheckBox">
|
||||
<property name="text">
|
||||
<string>Dither Color</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBox">
|
||||
<property name="text">
|
||||
<string>Dither Alpha</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_resize">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>249</width>
|
||||
<height>367</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Resize Options</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_mipmap">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>241</width>
|
||||
<height>357</height>
|
||||
</rect>
|
||||
</property>
|
||||
<attribute name="label">
|
||||
<string>Mipmap Options</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="spacing">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="generateMipmapsCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Generate mipmaps</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_8">
|
||||
<property name="spacing">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="mipmapFilterLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Filter:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>mipmapFilterComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="mipmapFilterComboBox">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>26</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Box</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Triangle</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Kaiser</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="mipmapFilterSettings">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="autoFillBackground">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="_9">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="limitMipmapsCheckBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Limit Mipmaps</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="maxLevelLabel">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Max Level:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>maxLevelSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="maxLevelSpinBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGraphicsView" name="graphicsView_2"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_11">
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -41,7 +41,7 @@
|
||||
|
||||
static bool loadImage(nv::Image & image, const char * fileName)
|
||||
{
|
||||
if (nv::strCaseCmp(nv::Path::extension(fileName), ".dds") == 0)
|
||||
if (nv::strCaseDiff(nv::Path::extension(fileName), ".dds") == 0)
|
||||
{
|
||||
nv::DirectDrawSurface dds(fileName);
|
||||
if (!dds.isValid())
|
||||
|
Reference in New Issue
Block a user