From ca8765ed79abff32804581f88c0f0b07ecfd368d Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Fri, 1 Dec 2006 02:51:56 +0000 Subject: [PATCH] - Removed all the "fast" and unused code from FColorMatcher. Today's computers are fast enough that the difference isn't even noticeable unless you're doing hundreds of thousands of matches, and I never had any plans to improve the algorithm the "fast" code used. - Fixed: BestColor() should not by default return 1 as a possible match, since it's normally the transparent color. SVN r400 (trunk) --- docs/rh-log.txt | 6 ++ src/colormatcher.cpp | 239 ++----------------------------------------- src/colormatcher.h | 28 ----- src/v_palette.h | 2 +- 4 files changed, 14 insertions(+), 261 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index c77937ff68..f86464ba15 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,4 +1,10 @@ November 30, 2006 +- Removed all the "fast" and unused code from FColorMatcher. Today's + computers are fast enough that the difference isn't even noticeable + unless you're doing hundreds of thousands of matches, and I never had + any plans to improve the algorithm the "fast" code used. +- Fixed: BestColor() should not by default return 1 as a possible match, + since it's normally the transparent color. - The DSimpleCanvas constructor now fills MemBuffer with zeros. - Fixed: If the FBTexture wasn't exactly the same size as the screen, D3DFB::PaintToWindow() would still lock it with D3DLOCK_DISCARD. Alas, diff --git a/src/colormatcher.cpp b/src/colormatcher.cpp index f489d1e030..3bd9a71ce6 100644 --- a/src/colormatcher.cpp +++ b/src/colormatcher.cpp @@ -30,8 +30,11 @@ ** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. **--------------------------------------------------------------------------- ** -** This tries to be a fast closest color finding system. It is, but the results -** are not as good as I would like, so I don't actually use it. +** Once upon a time, this tried to be a fast closest color finding system. +** It was, but the results were not as good as I would like, so I didn't +** actually use it. But I did keep the code around in case I ever felt like +** revisiting the problem. I never did, so now it's relegated to the mists +** of SVN history, and this is just a thin wrapper around BestColor(). ** */ @@ -40,29 +43,7 @@ #include "doomtype.h" #include "colormatcher.h" -#include "i_system.h" - -// Uncomment this to use the fast color lookup stuff. -// Unfortunately, it's not totally accurate. :-( -//#define BEFAST - -struct FColorMatcher::Seed -{ - BYTE r, g, b; - BYTE bad; - BYTE color; -}; - -struct FColorMatcher::PalEntry -{ -#ifndef WORDS_BIGENDIAN - BYTE b, g, r, a; -#else - BYTE a, r, g, b; -#endif -}; - -extern int BestColor (const uint32 *palette, int r, int g, int b, int first = 0, int num = 256); +#include "v_palette.h" FColorMatcher::FColorMatcher () { @@ -82,224 +63,18 @@ FColorMatcher::FColorMatcher (const FColorMatcher &other) FColorMatcher &FColorMatcher::operator= (const FColorMatcher &other) { Pal = other.Pal; - memcpy (FirstColor, other.FirstColor, sizeof(FirstColor)); - memcpy (NextColor, other.NextColor, sizeof(NextColor)); return *this; } void FColorMatcher::SetPalette (const DWORD *palette) { Pal = (const PalEntry *)palette; - - // 0 is the transparent color, so it is never a valid color - memset (FirstColor, 0, sizeof(FirstColor)); - memset (NextColor, 0, sizeof(NextColor)); - -#ifdef BEFAST - Seed seeds[255]; - BYTE seedspread[CHISIZE+1][CHISIZE+1][CHISIZE+1]; - int numseeds; - int i, radius; - - memset (seedspread, 255, sizeof(seedspread)); - numseeds = 0; - - // Plant each color from the palette as seeds in the color cube - for (i = 1; i < 256; i++) - { - int r = (Pal[i].r + CLOSIZE/2) >> CLOBITS; - int g = (Pal[i].g + CLOSIZE/2) >> CLOBITS; - int b = (Pal[i].b + CLOSIZE/2) >> CLOBITS; - - if (FirstColor[r][g][b] == 0) - { - seeds[numseeds].r = r; - seeds[numseeds].g = g; - seeds[numseeds].b = b; - seedspread[r][g][b] = numseeds; - numseeds++; - } - else - { - NextColor[i] = FirstColor[r][g][b]; - } - FirstColor[r][g][b] = i; - } - - for (i = numseeds-1; i >= 0; i--) - { - seeds[i].color = FirstColor[seeds[i].r][seeds[i].g][seeds[i].b]; - } - - // Grow each seed outward as a cube until no seed can - // grow any further. - for (radius = 1; radius < CHISIZE; radius++) - { - int seedsused = 0; - for (i = numseeds - 1; i >= 0; i--) - { - if (seeds[i].color == 0) - continue; - - seedsused++; - /* _ */ - int numhits = 0; /* _/| b (0,0,HISIZE) */ - /* _/ */ - int r1, r2, g1, g2, b1, b2; /* _/ */ - /* / */ - r1 = seeds[i].r - radius; /* +-------> r (HISIZE,0,0) */ - r2 = seeds[i].r + radius; /* |(0,0,0) */ - g1 = seeds[i].g - radius; /* | */ - g2 = seeds[i].g + radius; /* | */ - b1 = seeds[i].b - radius; /* | */ - b2 = seeds[i].b + radius; /* v g (0,HISIZE,0) */ - - // Check to see which planes are acceptable - BYTE bad = 0; - if (r1 < 0) bad |= 1, r1 = 0; - if (r2 > CHISIZE) bad |= 2, r2 = CHISIZE; - if (g1 < 0) bad |= 4, g1 = 0; - if (g2 > CHISIZE) bad |= 8, g2 = CHISIZE; - if (b1 < 0) bad |= 16, b1 = 0; - if (b2 > CHISIZE) bad |= 32, b2 = CHISIZE; - - bad |= seeds[i].bad; - - if (!(bad & 1)) // Do left green-blue plane - { - if (!FillPlane (r1, r1, g1, g2, b1, b2, seedspread, seeds, i)) - bad |= 1; - r1++; - } - - if (!(bad & 2)) // Do right green-blue plane - { - if (!FillPlane (r2, r2, g1, g2, b1, b2, seedspread, seeds, i)) - bad |= 2; - r2--; - } - - if (!(bad & 4)) // Do top red-blue plane - { - if (!FillPlane (r1, r2, g1, g1, b1, b2, seedspread, seeds, i)) - bad |= 4; - g1++; - } - - if (!(bad & 8)) // Do bottom red-blue plane - { - if (!FillPlane (r1, r2, g2, g2, b1, b2, seedspread, seeds, i)) - bad |= 8; - g2--; - } - - if (!(bad & 16)) // Do front red-green plane - { - if (!FillPlane (r1, r2, g1, g2, b1, b1, seedspread, seeds, i)) - bad |= 16; - } - - if (!(bad & 32)) // Do back red-green plane - { - if (!FillPlane (r1, r2, g1, g2, b2, b2, seedspread, seeds, i)) - bad |= 32; - } - - if (bad == 63) - { // This seed did not grow any further, so it can be deactivated - seeds[i].color = 0; - } - else - { // Remember which directions were blocked, so we don't - // try growing in those directions again in later passes. - seeds[i].bad = bad; - } - } - if (seedsused == 0) - { // No seeds grew during this pass, so we're done. - break; - } - } -#endif -} - -int FColorMatcher::FillPlane (int r1, int r2, int g1, int g2, int b1, int b2, - BYTE seedspread[CHISIZE+1][CHISIZE+1][CHISIZE+1], - Seed *seeds, int thisseed) -{ - const Seed *secnd = seeds + thisseed; - BYTE color = secnd->color; - int r, g, b; - int numhits = 0; - - for (r = r1; r <= r2; r++) - { - for (g = g1; g <= g2; g++) - { - for (b = b1; b <= b2; b++) - { - if (seedspread[r][g][b] == 255) - { - seedspread[r][g][b] = thisseed; - FirstColor[r][g][b] = color; - numhits++; - } - else - { - const Seed *first = seeds + seedspread[r][g][b]; - - int fr = r-first->r; - int fg = g-first->g; - int fb = b-first->b; - int sr = r-secnd->r; - int sg = g-secnd->g; - int sb = b-secnd->b; - if (fr*fr+fg*fg+fb*fb > sr*sr+sg*sg+sb*sb) - { - FirstColor[r][g][b] = color; - seedspread[r][g][b] = thisseed; - numhits++; - } - } - } - } - } - return numhits; } BYTE FColorMatcher::Pick (int r, int g, int b) { if (Pal == NULL) - return 0; + return 1; -#ifdef BEFAST - BYTE bestcolor; - int bestdist; - - BYTE color = FirstColor[(r+CLOSIZE/2)>>CLOBITS][(g+CLOSIZE/2)>>CLOBITS][(b+CLOSIZE/2)>>CLOBITS]; - if (NextColor[color] == 0) - return color; - - bestcolor = 0; - bestdist = 257*257+257*257+257*257; - - do - { - int dist = (r-Pal[color].r)*(r-Pal[color].r)+ - (g-Pal[color].g)*(g-Pal[color].g)+ - (b-Pal[color].b)*(b-Pal[color].b); - if (dist < bestdist) - { - if (dist == 0) - return color; - - bestdist = dist; - bestcolor = color; - } - color = NextColor[color]; - } while (color != 0); - return bestcolor; -#else return BestColor ((uint32 *)Pal, r, g, b); -#endif } diff --git a/src/colormatcher.h b/src/colormatcher.h index 449e484ba5..e166da0e11 100644 --- a/src/colormatcher.h +++ b/src/colormatcher.h @@ -34,24 +34,6 @@ #ifndef __COLORMATCHER_H__ #define __COLORMATCHER_H__ -// This class implements a "pretty good" color matcher for palettized images. -// In many cases, it is able to choose the "best" color with only a few -// comparisons. In all other cases, it chooses an "almost best" color in only -// a few comparisons. This is much faster than scanning the entire palette -// when you want to pick a color, so the somewhat lesser quality should be -// acceptable unless quality is the highest priority. -// -// The reason for the lesser quality is because this algorithm stores groups -// of colors into cells in a color cube and then spreads those color groups -// around into neighboring cells. When asked to pick a color, it looks in a -// single cell and sees which of the colors stored in that cell is closest -// to the requested color. For borderline cases, the chosen color may not -// actually be the best color in the entire palette, but it is still close. -// -// The accuracy of this class depends on the input palette and on HIBITS. -// HIBITS 4 seems to be a reasonable compromise between preprocessing time, -// space, and accuracy. - class FColorMatcher { public: @@ -64,17 +46,7 @@ public: FColorMatcher &operator= (const FColorMatcher &other); private: - enum { CHIBITS=4, CLOBITS=8-CHIBITS, CHISIZE=1<