mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2024-11-28 01:54:18 +01:00
Actually adhere to the wrap mode passed to the compressor
This commit is contained in:
parent
b7b9357964
commit
049ea129eb
@ -62,7 +62,11 @@
|
||||
#include "FasTC/Pixel.h"
|
||||
#include "FasTC/Color.h"
|
||||
|
||||
#ifndef NDEBUG
|
||||
# include "PVRTCImage.h"
|
||||
#endif
|
||||
#include "Block.h"
|
||||
#include "Indexer.h"
|
||||
|
||||
#define USE_CONSTANT_LUTS
|
||||
|
||||
@ -231,18 +235,26 @@ namespace PVRTCC {
|
||||
#define AssertPOT(x) (void)(0)
|
||||
#endif
|
||||
|
||||
static uint8 LookupIntensityByte(CompressionLabel *labels,
|
||||
const uint32 *pixels,
|
||||
uint32 index) {
|
||||
float i = 255.0f * LookupIntensity(labels, pixels, index);
|
||||
return static_cast<uint8>(i + 0.5f);
|
||||
}
|
||||
|
||||
static EExtremaResult ComputeLocalExtrema(
|
||||
CompressionLabel *labels, const uint8 *inBuf,
|
||||
const uint32 x, const uint32 y, const uint32 width, const uint32 height) {
|
||||
const uint32 x, const uint32 y, const Indexer &idxr) {
|
||||
|
||||
uint32 width = idxr.GetWidth();
|
||||
uint32 height = idxr.GetHeight();
|
||||
|
||||
AssertPOT(width);
|
||||
AssertPOT(height);
|
||||
|
||||
assert(x < width);
|
||||
assert(y < height);
|
||||
|
||||
const uint32 *pixels = reinterpret_cast<const uint32 *>(inBuf);
|
||||
uint8 i0 = static_cast<uint8>(255.0f * LookupIntensity(labels, pixels, y*width + x) + 0.5f);
|
||||
uint32 idx0 = idxr(x, y);
|
||||
uint8 i0 = LookupIntensityByte(labels, pixels, idx0);
|
||||
|
||||
int32 ng = 0;
|
||||
int32 nl = 0;
|
||||
@ -254,14 +266,10 @@ namespace PVRTCC {
|
||||
|
||||
if(i == 0 && j == 0) continue;
|
||||
|
||||
int32 xx = (i + static_cast<int32>(x + width)) & (width - 1);
|
||||
int32 yy = (j + static_cast<int32>(y + height)) & (height - 1);
|
||||
int32 xx = i + static_cast<int32>(x);
|
||||
int32 yy = j + static_cast<int32>(y);
|
||||
uint8 ix = LookupIntensityByte(labels, pixels, idxr(xx, yy));
|
||||
|
||||
assert(xx >= 0 && xx < static_cast<int32>(width));
|
||||
assert(yy >= 0 && yy < static_cast<int32>(height));
|
||||
|
||||
uint32 idx = static_cast<uint32>(xx) + width * static_cast<uint32>(yy);
|
||||
uint8 ix = static_cast<uint8>(255.0f * LookupIntensity(labels, pixels, idx) + 0.5f);
|
||||
if(ix >= i0) {
|
||||
ng++;
|
||||
}
|
||||
@ -276,15 +284,15 @@ namespace PVRTCC {
|
||||
return result;
|
||||
}
|
||||
|
||||
CompressionLabel &l = labels[y*width + x];
|
||||
CompressionLabel &l = labels[idx0];
|
||||
const int32 kThreshold = kKernelSz * kKernelSz - 1;
|
||||
if(ng >= kThreshold) {
|
||||
l.lowLabel.distance = 1;
|
||||
l.lowLabel.AddIdx(y*width+x);
|
||||
l.lowLabel.AddIdx(idx0);
|
||||
result = eExtremaResult_LocalMin;
|
||||
} else if(nl >= kThreshold) {
|
||||
l.highLabel.distance = 1;
|
||||
l.highLabel.AddIdx(y*width+x);
|
||||
l.highLabel.AddIdx(idx0);
|
||||
result = eExtremaResult_LocalMax;
|
||||
}
|
||||
|
||||
@ -351,23 +359,25 @@ namespace PVRTCC {
|
||||
|
||||
static void LabelImageForward(CompressionLabel *labels,
|
||||
const uint8 *inBuf,
|
||||
const uint32 w, const uint32 h) {
|
||||
const Indexer &idxr) {
|
||||
uint32 w = idxr.GetWidth();
|
||||
uint32 h = idxr.GetHeight();
|
||||
|
||||
AssertPOT(w);
|
||||
AssertPOT(h);
|
||||
|
||||
for(uint32 j = 0; j < h+3; j++) {
|
||||
for(uint32 i = 0; i < w; i++) {
|
||||
EExtremaResult result = ComputeLocalExtrema(labels, inBuf, i, j & (h - 1), w, h);
|
||||
EExtremaResult result = ComputeLocalExtrema(labels, inBuf, i, j, idxr);
|
||||
bool dilateMax = result != eExtremaResult_LocalMax;
|
||||
bool dilateMin = result != eExtremaResult_LocalMin;
|
||||
|
||||
if(dilateMax || dilateMin) {
|
||||
// Look up and to the left to determine the distance...
|
||||
uint32 upIdx = ((j+h-1) & (h - 1)) * w + i;
|
||||
uint32 leftIdx = (j & (h - 1)) * w + ((i+w-1) & (w - 1));
|
||||
uint32 upIdx = idxr(i, j - 1);
|
||||
uint32 leftIdx = idxr(i - 1, j);
|
||||
|
||||
CompressionLabel &l = labels[(j & (h - 1))*w + i];
|
||||
CompressionLabel &l = labels[idxr(i, j)];
|
||||
CompressionLabel &up = labels[upIdx];
|
||||
CompressionLabel &left = labels[leftIdx];
|
||||
|
||||
@ -431,8 +441,10 @@ namespace PVRTCC {
|
||||
#endif
|
||||
}
|
||||
|
||||
static void LabelImageBackward(CompressionLabel *labels,
|
||||
const uint32 w, const uint32 h) {
|
||||
static void LabelImageBackward(CompressionLabel *labels, const Indexer &idxr) {
|
||||
|
||||
uint32 w = idxr.GetWidth();
|
||||
uint32 h = idxr.GetHeight();
|
||||
|
||||
AssertPOT(w);
|
||||
AssertPOT(h);
|
||||
@ -441,22 +453,22 @@ namespace PVRTCC {
|
||||
for(int32 j = static_cast<int32>(h)+2; j >= 0; j--) {
|
||||
for(int32 i = static_cast<int32>(w)-1; i >= 0; i--) {
|
||||
|
||||
CompressionLabel &l = labels[(j & (h - 1)) * w + i];
|
||||
CompressionLabel &l = labels[idxr(i, j)];
|
||||
|
||||
// Add top right corner
|
||||
neighbors[0] = &(labels[((j + h - 1) & (h - 1)) * w + ((i + 1) & (w - 1))]);
|
||||
neighbors[0] = &(labels[idxr(i+1, j-1)]);
|
||||
|
||||
// Add right label
|
||||
neighbors[1] = &(labels[(j & (h - 1)) * w + ((i + 1) & (w - 1))]);
|
||||
neighbors[1] = &(labels[idxr(i+1, j)]);
|
||||
|
||||
// Add bottom right label
|
||||
neighbors[2] = &(labels[((j + 1) & (h - 1)) * w + ((i + 1) & (w - 1))]);
|
||||
neighbors[2] = &(labels[idxr(i+1, j+1)]);
|
||||
|
||||
// Add bottom label
|
||||
neighbors[3] = &(labels[((j + 1) & (h - 1)) * w + i]);
|
||||
neighbors[3] = &(labels[idxr(i, j+1)]);
|
||||
|
||||
// Add bottom left label
|
||||
neighbors[4] = &(labels[((j + 1) & (h - 1)) * w + ((i + w - 1) & (w - 1))]);
|
||||
neighbors[4] = &(labels[idxr(i-1, j+1)]);
|
||||
|
||||
DilateLabelBackward(l.highLabel, neighbors, true);
|
||||
DilateLabelBackward(l.lowLabel, neighbors, false);
|
||||
@ -464,60 +476,6 @@ namespace PVRTCC {
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void DilateImage(CompressionLabel *labels, const uint8 *inBuf, uint32 w, uint32 h) {
|
||||
for(uint32 j = 0; j < h; j++)
|
||||
for(uint32 i = 0; i < w; i++) {
|
||||
ComputeLocalExtrema(labels, inBuf, i, j, w, h);
|
||||
|
||||
uint32 idx = j*w + i;
|
||||
|
||||
uint32 minLowDist = labels[idx].lowLabel.distance == 0? 5 : labels[idx].lowLabel.distance - 1;
|
||||
uint32 minHighDist = labels[idx].highLabel.distance == 0? 5 : labels[idx].highLabel.distance - 1;
|
||||
|
||||
for(int32 y = 0; y < 3; y++)
|
||||
for(int32 x = 0; x < 3; x++) {
|
||||
uint32 cidx = ((j + y + h-1) & (h-1))*w + ((i+x+w-1) & (w-1));
|
||||
|
||||
if(labels[cidx].lowLabel.distance > 0)
|
||||
minLowDist = ::std::min<uint32>(minLowDist, labels[cidx].lowLabel.distance);
|
||||
|
||||
if(labels[cidx].highLabel.distance > 0)
|
||||
minHighDist = ::std::min<uint32>(minHighDist, labels[cidx].highLabel.distance);
|
||||
}
|
||||
|
||||
if(static_cast<int32>(minLowDist) != labels[idx].lowLabel.distance - 1) {
|
||||
labels[idx].lowLabel.nLabels = 0;
|
||||
}
|
||||
|
||||
if(static_cast<int32>(minHighDist) != labels[idx].highLabel.distance - 1) {
|
||||
labels[idx].highLabel.nLabels = 0;
|
||||
}
|
||||
|
||||
for(int32 y = 0; y < 3; y++)
|
||||
for(int32 x = 0; x < 3; x++) {
|
||||
uint32 cidx = ((j + y + h-1) & (h-1))*w + ((i+x+w-1) & (w-1));
|
||||
|
||||
if(minLowDist > 0 && labels[cidx].lowLabel.distance == minLowDist) {
|
||||
labels[idx].lowLabel.Combine(labels[cidx].lowLabel);
|
||||
}
|
||||
|
||||
if(minHighDist > 0 && labels[cidx].highLabel.distance == minHighDist) {
|
||||
labels[idx].highLabel.Combine(labels[cidx].highLabel);
|
||||
}
|
||||
}
|
||||
|
||||
if(minLowDist > 0 && minLowDist < 5) {
|
||||
labels[idx].lowLabel.distance = minLowDist + 1;
|
||||
}
|
||||
|
||||
if(minHighDist > 0 && minHighDist < 5) {
|
||||
labels[idx].highLabel.distance = minHighDist + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static FasTC::Color CollectLabel(const uint32 *pixels, const Label &label) {
|
||||
FasTC::Color ret;
|
||||
uint32 nPs = 0;
|
||||
@ -536,7 +494,10 @@ namespace PVRTCC {
|
||||
|
||||
static void GenerateLowHighImages(CompressionLabel *labels,
|
||||
const uint8 *inBuf, uint8 *outBuf,
|
||||
const uint32 w, const uint32 h) {
|
||||
const Indexer &idxr) {
|
||||
uint32 w = idxr.GetWidth();
|
||||
uint32 h = idxr.GetHeight();
|
||||
|
||||
assert((w % 4) == 0);
|
||||
assert((h % 4) == 0);
|
||||
AssertPOT(w);
|
||||
@ -556,7 +517,7 @@ namespace PVRTCC {
|
||||
for(uint32 y = j*4; y <= (j+1)*4; y++)
|
||||
for(uint32 x = i*4; x <= (i+1)*4; x++) {
|
||||
|
||||
uint32 idx = (y & (h-1))*w + (x & (w-1));
|
||||
uint32 idx = idxr(x, y);
|
||||
float intensity = labels[idx].intensity;
|
||||
if(intensity < minIntensity) {
|
||||
minIntensity = intensity;
|
||||
@ -616,9 +577,10 @@ namespace PVRTCC {
|
||||
#endif
|
||||
// Average all of the values together now...
|
||||
FasTC::Color high, low;
|
||||
for(uint32 y = 0; y < 4; y++)
|
||||
for(uint32 x = 0; x < 4; x++) {
|
||||
uint32 idx = y * 4 + x;
|
||||
Indexer localIdxr(4, 4);
|
||||
for(uint32 y = 0; y < localIdxr.GetHeight(); y++)
|
||||
for(uint32 x = 0; x < localIdxr.GetWidth(); x++) {
|
||||
uint32 idx = localIdxr(x, y);
|
||||
FasTC::Color c = blockColors[0][idx];
|
||||
if(c.A() < 0.0f) {
|
||||
c.Unpack(pixels[maxIntensityIdx]);
|
||||
@ -699,7 +661,10 @@ namespace PVRTCC {
|
||||
}
|
||||
}
|
||||
|
||||
static void GenerateModulationValues(uint8 *outBuf, const uint8 *inBuf, uint32 w, uint32 h) {
|
||||
static void GenerateModulationValues(uint8 *outBuf, const uint8 *inBuf,
|
||||
const Indexer &idxr) {
|
||||
uint32 w = idxr.GetWidth();
|
||||
uint32 h = idxr.GetHeight();
|
||||
|
||||
AssertPOT(w);
|
||||
AssertPOT(h);
|
||||
@ -715,13 +680,14 @@ namespace PVRTCC {
|
||||
// every iteration of the loop. Once we finish with a block, topLeft becomes topRight and
|
||||
// bottomLeft becomes bottomRight. Also, when we go to the next row, bottomRight becomes
|
||||
// topLeft.
|
||||
Indexer blkIdxr(blocksW, blocksH, idxr.GetWrapMode());
|
||||
for(uint32 j = 0; j < blocksH; j++) {
|
||||
for(uint32 i = 0; i < blocksW; i++) {
|
||||
|
||||
const int32 lowXIdx = i;
|
||||
const int32 highXIdx = (i + 1) & (blocksW - 1);
|
||||
const int32 highXIdx = blkIdxr.ResolveX(i + 1);
|
||||
const int32 lowYIdx = j;
|
||||
const int32 highYIdx = (j + 1) & (blocksH - 1);
|
||||
const int32 highYIdx = blkIdxr.ResolveY(j + 1);
|
||||
|
||||
const uint32 topLeftBlockIdx = GetBlockIndex(lowXIdx, lowYIdx);
|
||||
const uint32 topRightBlockIdx = GetBlockIndex(highXIdx, lowYIdx);
|
||||
@ -759,8 +725,8 @@ namespace PVRTCC {
|
||||
|
||||
for(uint32 y = 0; y < 4; y++) {
|
||||
for(uint32 x = 0; x < 4; x++) {
|
||||
uint32 pixelX = (i*4 + 2 + x) & (w - 1);
|
||||
uint32 pixelY = (j*4 + 2 + y) & (h - 1);
|
||||
uint32 pixelX = idxr.ResolveX(i*4 + 2 + x);
|
||||
uint32 pixelY = idxr.ResolveY(j*4 + 2 + y);
|
||||
FasTC::Pixel colorA = BilerpPixels(x, y, topLeftA, topRightA, bottomLeftA, bottomRightA);
|
||||
FasTC::Pixel colorB = BilerpPixels(x, y, topLeftB, topRightB, bottomLeftB, bottomRightB);
|
||||
FasTC::Pixel original(pixels[pixelY * w + pixelX]);
|
||||
@ -938,8 +904,10 @@ namespace PVRTCC {
|
||||
CompressionLabel *labels =
|
||||
(CompressionLabel *)calloc(width * height, sizeof(CompressionLabel));
|
||||
|
||||
Indexer idxr(width, height, wrapMode);
|
||||
|
||||
// First traverse forward...
|
||||
LabelImageForward(labels, cj.InBuf(), width, height);
|
||||
LabelImageForward(labels, cj.InBuf(), idxr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
gDbgPixels = reinterpret_cast<const uint32 *>(cj.InBuf());
|
||||
@ -961,7 +929,7 @@ namespace PVRTCC {
|
||||
#endif
|
||||
|
||||
// Then traverse backward...
|
||||
LabelImageBackward(labels, width, height);
|
||||
LabelImageBackward(labels, idxr);
|
||||
|
||||
#ifndef NDEBUG
|
||||
DebugOutputLabels("Backward-", labels, width, height);
|
||||
@ -992,10 +960,10 @@ namespace PVRTCC {
|
||||
#endif
|
||||
|
||||
// Then combine everything...
|
||||
GenerateLowHighImages(labels, cj.InBuf(), cj.OutBuf(), width, height);
|
||||
GenerateLowHighImages(labels, cj.InBuf(), cj.OutBuf(), idxr);
|
||||
|
||||
// Then compute modulation values
|
||||
GenerateModulationValues(cj.OutBuf(), cj.InBuf(), width, height);
|
||||
GenerateModulationValues(cj.OutBuf(), cj.InBuf(), idxr);
|
||||
|
||||
// Cleanup
|
||||
free(labels);
|
||||
|
118
PVRTCEncoder/src/Indexer.h
Normal file
118
PVRTCEncoder/src/Indexer.h
Normal file
@ -0,0 +1,118 @@
|
||||
/* FasTC
|
||||
* Copyright (c) 2013 University of North Carolina at Chapel Hill.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software and its
|
||||
* documentation for educational, research, and non-profit purposes, without
|
||||
* fee, and without a written agreement is hereby granted, provided that the
|
||||
* above copyright notice, this paragraph, and the following four paragraphs
|
||||
* appear in all copies.
|
||||
*
|
||||
* Permission to incorporate this software into commercial products may be
|
||||
* obtained by contacting the authors or the Office of Technology Development
|
||||
* at the University of North Carolina at Chapel Hill <otd@unc.edu>.
|
||||
*
|
||||
* This software program and documentation are copyrighted by the University of
|
||||
* North Carolina at Chapel Hill. The software program and documentation are
|
||||
* supplied "as is," without any accompanying services from the University of
|
||||
* North Carolina at Chapel Hill or the authors. The University of North
|
||||
* Carolina at Chapel Hill and the authors do not warrant that the operation of
|
||||
* the program will be uninterrupted or error-free. The end-user understands
|
||||
* that the program was developed for research purposes and is advised not to
|
||||
* rely exclusively on the program for any reason.
|
||||
*
|
||||
* IN NO EVENT SHALL THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL OR THE
|
||||
* AUTHORS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL,
|
||||
* OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
|
||||
* THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF NORTH CAROLINA
|
||||
* AT CHAPEL HILL OR THE AUTHORS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
* DAMAGE.
|
||||
*
|
||||
* THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND THE AUTHORS SPECIFICALLY
|
||||
* DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE AND ANY
|
||||
* STATUTORY WARRANTY OF NON-INFRINGEMENT. THE SOFTWARE PROVIDED HEREUNDER IS ON
|
||||
* AN "AS IS" BASIS, AND THE UNIVERSITY OF NORTH CAROLINA AT CHAPEL HILL AND
|
||||
* THE AUTHORS HAVE NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
|
||||
* ENHANCEMENTS, OR MODIFICATIONS.
|
||||
*
|
||||
* Please send all BUG REPORTS to <pavel@cs.unc.edu>.
|
||||
*
|
||||
* The authors may be contacted via:
|
||||
*
|
||||
* Pavel Krajcevski
|
||||
* Dept of Computer Science
|
||||
* 201 S Columbia St
|
||||
* Frederick P. Brooks, Jr. Computer Science Bldg
|
||||
* Chapel Hill, NC 27599-3175
|
||||
* USA
|
||||
*
|
||||
* <http://gamma.cs.unc.edu/FasTC/>
|
||||
*/
|
||||
|
||||
#ifndef PVRTCENCODER_SRC_INDEXER_H_
|
||||
#define PVRTCENCODER_SRC_INDEXER_H_
|
||||
|
||||
#include "FasTC/PVRTCCompressor.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
namespace PVRTCC {
|
||||
|
||||
class Indexer {
|
||||
private:
|
||||
const EWrapMode m_WrapMode;
|
||||
const uint32 m_Width;
|
||||
const uint32 m_Height;
|
||||
|
||||
uint32 Resolve(int32 i, uint32 limit) const {
|
||||
int32 r;
|
||||
switch(m_WrapMode) {
|
||||
case eWrapMode_Clamp:
|
||||
r = static_cast<uint32>(std::max(0, std::min<int32>(i, limit)));
|
||||
break;
|
||||
|
||||
case eWrapMode_Wrap:
|
||||
{
|
||||
r = i;
|
||||
int32 l = static_cast<int32>(limit);
|
||||
while (r >= l) { r -= l; }
|
||||
while (r < 0) { r += l; }
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
assert (r >= 0);
|
||||
assert (r < limit);
|
||||
return r;
|
||||
}
|
||||
|
||||
public:
|
||||
Indexer(uint32 width, uint32 height, EWrapMode wrapMode = eWrapMode_Wrap)
|
||||
: m_WrapMode(wrapMode)
|
||||
, m_Width(width)
|
||||
, m_Height(height)
|
||||
{ }
|
||||
|
||||
uint32 GetWidth() const { return this->m_Width; }
|
||||
uint32 GetHeight() const { return this->m_Height; }
|
||||
EWrapMode GetWrapMode() const { return this->m_WrapMode; }
|
||||
|
||||
uint32 ResolveX(int32 i) const { return Resolve(i, this->m_Width); }
|
||||
uint32 ResolveY(int32 i) const { return Resolve(i, this->m_Height); }
|
||||
|
||||
uint32 operator()(int32 i, int32 j) const {
|
||||
uint32 _i = this->ResolveX(i);
|
||||
uint32 _j = this->ResolveY(j);
|
||||
|
||||
uint32 index = _j * this->m_Width + _i;
|
||||
assert (index < this->m_Width * this->m_Height);
|
||||
assert (index >= 0);
|
||||
return index;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PVRTCC
|
||||
|
||||
#endif // PVRTCENCODER_SRC_INDEXER_H_
|
Loading…
Reference in New Issue
Block a user