home *** CD-ROM | disk | FTP | other *** search
- Newsgroups: comp.sys.mac.programmer
- Path: sparky!uunet!gumby!kzoo!k044477
- From: k044477@hobbes.kzoo.edu (Jamie R. McCarthy)
- Subject: ColorTables: misc. tidbits and code
- Message-ID: <1992Sep3.163209.14917@hobbes.kzoo.edu>
- Organization: Kalamazoo College
- Date: Thu, 3 Sep 1992 16:32:09 GMT
- Lines: 822
-
- This article starts off with some AppleLink mail from Forrest Tanaka,
- telling you more than you ever wanted to know about color tables, and
- ends with a fair amount of ANSI C source code for manipulating them.
- This is, in short, a hodgepodge of answers and solutions. If you're
- a little confused about color graphics on the Mac (who isn't?!),
- well, who knows--this may clear up something for you.
-
- Please note that the code is copyrighted and may not be used directly
- in a for-profit program. That's 'cause my company paid me to write
- it and it's not fair for you to steal it. Sorry. If you want to use
- it, fix a bug for me. (There must be at least one.) Otherwise,
- you're free to use it directly in private or free programs, and to
- write your own code based on mine.
-
- Comments, especially on the source code, are heartily welcomed.
-
- Jamie McCarthy Internet: k044477@kzoo.edu AppleLink: j.mccarthy
-
-
-
-
-
- Item 5744291 10-July-92 16:02PDT
- From: DEVSUPPORTJ Developer Support Center
- To: J.MCCARTHYJ MCE-Lawrence Prod, J McCarthy
- Sub: RE-ColorTable code-level Q's
-
- July 10, 1992
-
- Hi Jamie
-
- I received your questions about color tables, and since there are
- several questions, IUll put the text of your question in a narrow
- paragraph and respond to each one in the normal paragraphs
- afterwards.
-
- When drawing offscreen, every CQD routine will handle both
- indexed and sequential tables properly; in addition,
- CopyBits will handle a "paletted" table for its source
- PixMap. Right?
-
- Yes. If the source PixMap to CopyBits is paletted and the destination
- is a window with a palette, then CopyBits uses the value field of
- each ColorSpec record as a palette index for each pixel, which is of
- course the whole idea behind paletted color tables. If the
- destination is anything else, then bit 14 of ctFlags is ignored and
- the color table is treated as either indexed or sequential depending
- on the value of bit 15. Bit 14 is also ignored when its color
- tableUs PixMap is used as the destination to CopyBits.
-
- IM V-136, contradictorially, says "The ctFlags field is
- significant for gDevices only," and "Color tables that are
- part of [non-GDevice] pixMaps have this bit clear." What
- this means is, "Clear your own ctFlags, use indexed tables,
- and don't mess with a GDevice's ctFlags." Right?
-
- Inside Macintosh is simply wrong on this point, though it was the
- popular belief for quite a while. The truth is that QuickDraw reads
- ctFlags regardless of whether the color tableUs PixMap belongs to a
- GDevice, a GWorld, or is one that you created. If you create your
- own PixMap and want to use a sequential color table, set this bit.
- If you want an indexed color table, clear this bit. QuickDraw will
- read this bit and do the right thing. I personally always make
- indexed color tables because I happen to be more comfortable with
- them, but you can make a sequential one if you want, and QuickDraw
- will have no problems with it.
-
- ItUs true that all screen GDevices have color tables which are
- sequential, but that doesnUt mean that all GDevices must have
- sequential color tables. If you make a GDevice yourself, say for
- off-screen drawing, then you can have either a sequential or indexed
- color table. QuickDraw will read the most significant bit of ctFlags
- and act accordingly.
-
-
- I understand that video drivers expect sequential tables.
- But, is there anything at all wrong with mixing and
- matching sequential and indexed tables when they don't
- belong to GDevices?
-
- No, no problem at all. In fact, as I mentioned, you can mix and match
- even if a color table belongs to a GDevice. The only thing you canUt
- do is change the color table of a screenUs GDevice directly.
-
-
- Must an indexed table be sorted?
-
- No. You can arrange an indexed color table in random order if you
- want to, as long as you set the value field of each the color
- specification records to the pixel value that you want for each
- color. For example, these two four-entry color tables are identical
- assuming ctFlags is zero:
-
- Entry value rgb Entry value rgb
- 0 0 white 0 2 mauve
- 1 1 green 1 1 green
- 2 2 mauve 2 3 black
- 3 3 black 3 0 white
-
-
- IM V-138 says "...when the Color2Index routine is called,
- it can find the best match to the full 48-bit resolution
- available in a colorSpec." Really? Even if the inverse
- table's only 3 bits and my color table consists of (for
- example) a 256-shade gradation from black to white?
- Doesn't that require appending a whole lot of information
- after the inverse table?
-
- Inside Macintosh is right, and so are you. If you have two colors
- that differ only in the least significant bit of each of their
- components, Color2Index will be able to tell the difference. The
- inverse-table look-up is just the first step; itUs a coarse
- estimation of what the final pixel value is. At the end of the
- inverse table is a linked list of colors, called the hidden-color
- list. After the inverse-table look-up is complete, this coarse
- estimate is fine-tuned using the hidden-color list so that
- Color2Index can tell the difference between two colors down to the
- last bit. Color QuickDraw doesnUt always use the hidden-color list
- though. If you use the arithmetic modes with CopyBits, only the
- coarse, inverse-table look-up is done. If you use dithering with
- CopyBits, the hidden-color list isnUt used either.
-
-
- What will happen if you ask CQD to manipulate a table whose
- top two ctFlags bits are 11? (Just out of curiosity.)
-
- IUve done this, and itUs fine. If the PixMap that owns this color
- table is used as a source to CopyBits and if the destination is a
- window with a palette, this PixMap is treated as a paletted color
- table. If the destination is a window without a palette or a PixMap
- thatUs not associated with a window at all, the color table is
- treated as a sequential color table. If the PixMap is used as the
- destination to CopyBits, then itUs just treated as a sequential color
- table. Think of it this way: bit 14 has an effect if the color table
- belongs to the source PixMap to CopyBits and a window with a palette
- is the destination. In any other case, bit 14 is ignored and bit 15
- tells QuickDraw what to do.
-
-
- Well, I hope that covers everything. If you need any clarifications
- or any more help, just let me know!
-
- -- Forrest
-
-
-
-
-
- /*
- * ColorTableUtils.h
- *
- * Copyright ) 1992 by Lawrence Productions, Inc. All Rights Reserved.
- *
- * This code may not be used in any for-profit program without the
- * written permission of Lawrence Productions, Inc.
- *
- */
-
-
-
- /********************************/
-
- #pragma once
-
- /********************************/
-
- /*
- * Note that the values of these three constants happen to equal the
- * top two bits of the ctFlags field. The macro for getColorTableMode()
- * is the only thing that depends on this fact.
- */
-
- enum {
- kIndexedColorTable = 0x00,
- kPalettedColorTable = 0x01,
- kSequentialColorTable = 0x02
- } ;
-
- /********************************/
-
- /*
- * Determine the mode of a color table.
- */
-
- short getColorTableMode(CTabPtr theTablePtr);
- #define getColorTableMode(theTablePtr) ( \
- ((unsigned short)(theTablePtr)->ctFlags) >> 14 )
- #define colorTableIsIndexed(theTablePtr) \
- (getColorTableMode(theTablePtr) == kIndexedColorTable)
- #define colorTableIsPaletted(theTablePtr) \
- (getColorTableMode(theTablePtr) == kPalettedColorTable)
- #define colorTableIsSequential(theTablePtr) \
- (getColorTableMode(theTablePtr) == kSequentialColorTable)
-
-
- /*
- * Determine whether a color table is sorted. Naturally, it's designed
- * for indexed tables, but works (trivially) with sequential and
- * paletted tables too.
- */
-
- Boolean colorTableIsSorted(CTabPtr theTable);
- #define assertColorTableIsSorted(theTable) ASSERT(colorTableIsSorted(theTable));
-
-
- /*
- * Find an entry's offset in a color table. Naturally, it's designed
- * for indexed tables, but works (trivially) on sequential tables too.
- * Paletted tables may have none or several entries that point to a
- * particular palette entry, and this routine will not attempt to
- * search them, returning kNoEntryFound instead.
- *
- * For all tables, the output is the index into the ctTable field.
- */
-
- #define kNoEntryFound (-1)
- short findEntryInSortedTable(CTabPtr theTable, short wEntry);
-
-
- /*
- * Add an entry to a color table. Returns TRUE if the entry was
- * actually added (i.e. if the table's size went up), and FALSE if
- * the entry wasn't added. The entry number is of course in the
- * value field.
- *
- * For this one, the table really _does_ have to be indexed.
- */
-
- Boolean addEntryToSortedIndexedTable(CTabHandle theIndexedTable, ColorSpec *theColorSpec);
-
-
- /*
- * Convert color storage modes back 'n' forth. These allocate memory
- * and don't alter the original table.
- *
- * You can't switch to or from a paletted color table without knowing
- * what the palette is, so no routines are provided for that.
- */
-
- CTabHandle makeIndexedFromSequential(CTabHandle theSequentialTable);
- CTabHandle makeSequentialFromSortedIndexed(CTabHandle theIndexedTable, RGBColor *fillColor);
-
-
- /*
- * Sort a table's entries. Does nothing if the table is sequential
- * or paletted.
- */
-
- void sortIndexedTable(CTabHandle theTable);
-
-
- /*
- * Compare two tables, even if they use different modes. Paletted
- * tables can't be compared to anything, and so always return FALSE.
- * If both tables are indexed, they must both be sorted.
- */
-
- Boolean colorTablesAreEquivalent(CTabHandle table1, CTabHandle table2, RGBColor *fillColor);
-
-
- /*
- * Functions to manipulate the number of entries of a color table.
- * The "get" function is simple, so it comes with a macro. The
- * others alter the ctSize field and resize the handle; "set"
- * sets the number of entries directly, while "change" adds or
- * subtracts from the current number of entries. If the table's
- * size changes, it (and memory) may be moved, even if it's
- * locked. If the table is lengthened, the new entries contain
- * garbage.
- */
-
- short getNCTEntries(CTabPtr theTable);
- #define getNCTEntries(theTable) ((theTable)->ctSize+1)
- void setNCTEntries(CTabHandle theTable, short nEntries);
- void changeNCTEntries(CTabHandle theTable, short nEntries);
-
-
- /*
- * Quickie macros to convert a table's depth to the maximum number of
- * entries, and to convert a number of entries to a minimum depth.
- *
- * The function prototypes are only there to do a little parameter
- * type-checking; since the macros do their conversion in place,
- * the functions wouldn't actually do anything if you were to call
- * them. (And if they took pointers instead of doing the work in
- * place, you couldn't use register variables, ick.) If the functions
- * ever actually _do_ get called, they pop into the debugger with
- * an appropriate message.
- */
-
- void convertDepthToMaxNEntries(short d, short n);
- #define convertDepthToMaxNEntries(d,n) \
- { short ___depth=(d); \
- for ((n)=1; ___depth>=1; --___depth) \
- (n) <<= 1; }
-
- void convertNEntriesToMinDepth(short n, short d);
- #define convertNEntriesToMinDepth(n,d) \
- { short ___nEntries=(n); \
- for ((d)=0; ___nEntries>1; ___nEntries>>=1) \
- ++(d); }
-
-
-
-
-
- /*
- * ColorTableUtils.c
- *
- * Copyright ) 1992 by Lawrence Productions, Inc. All Rights Reserved.
- *
- * This code may not be used in any for-profit program without the
- * written permission of Lawrence Productions, Inc.
- *
- */
-
-
-
- /********************************/
-
- #include "ColorTableUtils.h"
-
- /********************************/
-
- /*
- * You'll need to put qsort.c in your project.
- */
- #include <stdlib.h>
-
- /********************************/
-
- /*
- * The only thing used from JamieUtilities.c is "jmemcmp()," which is
- * just a clone of memcmp(). (I save 100 bytes of object code by
- * taking it out of mem.c, because memcmp() is the only function in
- * there that I would ever use. I guess I'm a fanatic.) Anyway, if
- * you don't have JamieUtilities, just #include <string.h>, drop mem.c
- * in your project, and change "jmemcmp" to "memcmp".
- */
- #include <JamieUtilities.h>
-
- /********************************/
-
-
-
- short (getColorTableMode)(CTabPtr theTable)
- {
- ASSERT(theTable != NULL);
-
- switch ( ((unsigned short) (theTable)->ctFlags) >> 14 ) {
-
- case 0x00: return kIndexedColorTable; break;
- case 0x01: return kPalettedColorTable; break;
- case 0x02: return kSequentialColorTable; break;
- default: ASSERT(0); return -1; break;
-
- }
- }
-
-
-
- Boolean colorTableIsSorted(CTabPtr theTable)
- {
- register ColorSpec *theCTTable;
- register short cPosition, nEntriesMinusOne, lastEntry;
-
- ASSERT(theTable != NULL);
-
- if (!colorTableIsIndexed(theTable)) {
- return TRUE;
- }
-
- theCTTable = &theTable->ctTable[0];
- nEntriesMinusOne = theTable->ctSize;
- cPosition = 0;
- lastEntry = -1;
- for (cPosition = 0; cPosition <= nEntriesMinusOne; ++cPosition) {
-
- register short thisEntry;
-
- if ( (thisEntry=theCTTable[cPosition].value) < lastEntry) {
- return FALSE;
- } else {
- lastEntry = thisEntry;
- }
-
- }
-
- return TRUE;
- }
-
-
-
- /*
- * Returns TRUE iff the entry was found. If the entry was not found,
- * it returns the position where it should be inserted.
- */
-
- Boolean engineFindEntryInSortedTable(CTabPtr tablePtr, register short wEntry, short *thePosition);
- Boolean engineFindEntryInSortedTable(CTabPtr tablePtr, register short wEntry, short *thePosition)
- {
- /*
- * I'm 99.9% sure this code will find an existing entry, but only
- * 80% sure that it'll return the proper position for a nonexisting
- * one, the proper position being the entry to the right. I suppose
- * I should test it rigorously one of these days...
- */
-
- register unsigned short cPosition;
- register unsigned short leftBounds, rightBounds;
- register ColorSpec *theCSpecArray;
-
- if (!colorTableIsIndexed(tablePtr)) {
- if (wEntry <= tablePtr->ctSize) {
- *thePosition = wEntry;
- return TRUE;
- } else {
- *thePosition = tablePtr->ctSize;
- return FALSE;
- }
- }
-
- assertColorTableIsSorted(tablePtr);
-
- theCSpecArray = tablePtr->ctTable;
- leftBounds = 0; rightBounds = tablePtr->ctSize + 1 - 1;
- cPosition = rightBounds / 2;
-
- while (leftBounds < rightBounds) {
-
- if (theCSpecArray[cPosition].value == wEntry) {
- *thePosition = cPosition;
- return TRUE;
- } else {
- if (theCSpecArray[cPosition].value < wEntry) {
- leftBounds = cPosition;
- cPosition += rightBounds + 1;
- cPosition >>= 1;
- } else {
- rightBounds = cPosition;
- cPosition += leftBounds;
- cPosition >>= 1;
- }
- }
-
- }
-
- /*
- * If the requested entry is not there, we want the entry that's
- * right _after_ where it would go.
- */
-
- if (theCSpecArray[cPosition].value < wEntry) {
- ++cPosition;
- }
-
- ASSERT(cPosition == tablePtr->ctSize+1 || theCSpecArray[cPosition].value > wEntry);
- ASSERT(cPosition == 0 || theCSpecArray[cPosition-1].value < wEntry);
-
- *thePosition = cPosition;
- return FALSE;
- }
-
-
- short findEntryInSortedTable(CTabPtr theTable, short wEntry)
- {
- short thePosition;
-
- if (engineFindEntryInSortedTable(theTable, wEntry, &thePosition)) {
- return thePosition;
- } else {
- return kNoEntryFound;
- }
- }
-
-
-
- Boolean addEntryToSortedIndexedTable(CTabHandle theIndexedTable, ColorSpec *theColorSpec)
- {
- register CTabPtr theIndexedTabPtr;
- short wEntry;
- short thePosition;
-
- ASSERT( colorTableIsIndexed(*theIndexedTable) );
-
- wEntry = theColorSpec->value;
-
- theIndexedTabPtr = *theIndexedTable;
- if (engineFindEntryInSortedTable(theIndexedTabPtr, wEntry, &thePosition)) {
-
- /* No need to add the entry, it's already there. */
-
- theIndexedTabPtr->ctTable[thePosition] = *theColorSpec;
-
- return FALSE;
-
- } else {
-
- long newSize;
-
- newSize = sizeof(ColorTable)
- + sizeof(ColorSpec) * ( theIndexedTabPtr->ctSize + 1 );
- SetHandleSize( (Handle) theIndexedTable, newSize );
- theIndexedTabPtr = *theIndexedTable;
-
- BlockMove( &theIndexedTabPtr->ctTable[thePosition],
- &theIndexedTabPtr->ctTable[thePosition]+1,
- (theIndexedTabPtr->ctSize+1 - thePosition) * sizeof(ColorSpec) );
-
- theIndexedTabPtr->ctTable[thePosition] = *theColorSpec;
-
- return TRUE;
-
- }
- }
-
-
-
- CTabHandle makeIndexedFromSequential(CTabHandle theSequentialTable)
- {
- CTabHandle theIndexedTable;
- register ColorSpec *theSequentialColorSpecPtr;
- register ColorSpec *theIndexedColorSpecPtr;
- register CTabPtr theSequentialTablePtr;
- register CTabPtr theIndexedTablePtr;
- register short cIndexedEntry;
- register short nSequentialEntriesMinusOne;
-
- ASSERT(theSequentialTable != NULL);
- ASSERT(colorTableIsSequential(*theSequentialTable));
-
- nSequentialEntriesMinusOne = (**theSequentialTable).ctSize;
-
- theIndexedTable = (CTabHandle) NewHandle( sizeof(ColorTable)
- + sizeof(ColorSpec) * nSequentialEntriesMinusOne );
- theIndexedTablePtr = *theIndexedTable;
- theSequentialTablePtr = *theSequentialTable;
-
- theIndexedTablePtr->ctSeed = theSequentialTablePtr->ctSeed;
- theIndexedTablePtr->ctFlags = theSequentialTablePtr->ctFlags
- & 0x3FFF
- | 0x0000;
- theIndexedTablePtr->ctSize = nSequentialEntriesMinusOne;
- theIndexedColorSpecPtr = &theIndexedTablePtr->ctTable[0];
- theSequentialColorSpecPtr = &theSequentialTablePtr->ctTable[0];
-
- for (cIndexedEntry = 0;
- cIndexedEntry <= nSequentialEntriesMinusOne;
- ++cIndexedEntry) {
-
- theIndexedColorSpecPtr->value = cIndexedEntry;
- (theIndexedColorSpecPtr++)->rgb = (theSequentialColorSpecPtr++)->rgb;
-
- }
-
- return theIndexedTable;
- }
-
-
-
- CTabHandle makeSequentialFromSortedIndexed(CTabHandle theIndexedTable, RGBColor *fillColor)
- {
- CTabHandle theSequentialTable;
- register ColorSpec *theIndexedColorSpecPtr;
- register ColorSpec *theSequentialColorSpecPtr;
- register CTabPtr theIndexedTablePtr;
- register CTabPtr theSequentialTablePtr;
- register short cSequentialEntry, nextIndexedEntry, nextIndexedPosition;
- register short nIndexedEntriesMinusOne, nSequentialEntriesMinusOne;
-
- ASSERT(theIndexedTable != NULL);
- ASSERT(colorTableIsIndexed(*theIndexedTable));
- assertColorTableIsSorted(*theIndexedTable);
-
- nIndexedEntriesMinusOne = (**theIndexedTable).ctSize;
- nSequentialEntriesMinusOne =
- (**theIndexedTable).ctTable[nIndexedEntriesMinusOne].value;
-
- theSequentialTable = (CTabHandle) NewHandle( sizeof(ColorTable)
- + sizeof(ColorSpec) * nSequentialEntriesMinusOne );
- theSequentialTablePtr = *theSequentialTable;
- theIndexedTablePtr = *theIndexedTable;
-
- theSequentialTablePtr->ctSeed = theIndexedTablePtr->ctSeed;
- theSequentialTablePtr->ctFlags = theIndexedTablePtr->ctFlags
- & 0x3FFF
- | 0x8000;
- theSequentialTablePtr->ctSize = nSequentialEntriesMinusOne;
- theSequentialColorSpecPtr = &theSequentialTablePtr->ctTable[0];
- theIndexedColorSpecPtr = &theIndexedTablePtr->ctTable[0];
-
- nextIndexedPosition = 0;
- nextIndexedEntry = theIndexedColorSpecPtr[0].value;
- for (cSequentialEntry = 0;
- cSequentialEntry <= nSequentialEntriesMinusOne;
- ++cSequentialEntry) {
-
- ASSERT(cSequentialEntry <= nextIndexedEntry);
-
- if (cSequentialEntry == nextIndexedEntry) {
- theSequentialColorSpecPtr->value = cSequentialEntry;
- (theSequentialColorSpecPtr++)->rgb = (theIndexedColorSpecPtr++)->rgb;
- if (++nextIndexedPosition > nIndexedEntriesMinusOne) {
- nextIndexedEntry = MAXINT;
- } else {
- nextIndexedEntry = theIndexedColorSpecPtr->value;
- }
- } else {
- theSequentialColorSpecPtr->value = 0;
- (theSequentialColorSpecPtr++)->rgb = *fillColor;
- }
-
- }
-
- return theSequentialTable;
- }
-
-
-
- static int compareColorSpecValues(const ColorSpec *color1, const ColorSpec *color2);
- static int compareColorSpecValues(register const ColorSpec *color1,
- register const ColorSpec *color2)
- {
- if (color1->value != color2->value) {
- if (color1->value < color2->value) {
- return -1;
- } else {
- return 1;
- }
- }
- return 0;
- }
-
- void sortIndexedTable(CTabHandle theTable)
- {
- register CTabPtr theTablePtr;
- short oldState;
-
- ASSERT(theTable != NULL);
-
- theTablePtr = *theTable;
- if (!colorTableIsIndexed(theTablePtr)) {
- return ;
- }
-
- oldState = HGetState( (Handle) theTable );
- HLock( (Handle) theTable);
- qsort( &theTablePtr->ctTable[0],
- theTablePtr->ctSize+1,
- sizeof(ColorSpec),
- (__cmp_func) compareColorSpecValues);
- HSetState( (Handle) theTable, oldState );
-
- assertColorTableIsSorted(theTablePtr);
- }
-
-
-
- Boolean colorTablesAreEquivalent(CTabHandle table1, CTabHandle table2, RGBColor *fillColor)
- {
- Boolean areEquivalent;
-
- ASSERT(table1 != NULL);
- ASSERT(table2 != NULL);
-
- areEquivalent = TRUE;
-
- if (colorTableIsPaletted(*table1) || colorTableIsPaletted(*table2)) {
- /* Paletted tables can't be compared to anything. */
- return FALSE;
- }
-
- if (colorTableIsSequential(*table1) || colorTableIsSequential(*table2)) {
-
- /*
- * Convert one of the tables to sequential, if need be, and compare.
- */
-
- register CTabPtr t1, t2;
- register short nEntriesMinusOne;
- CTabHandle convertedTable;
-
- convertedTable = NULL;
- if (colorTableIsIndexed(*table1)) {
- assertColorTableIsSorted(*table1);
- convertedTable = makeSequentialFromSortedIndexed(table1, fillColor);
- t1 = *convertedTable;
- t2 = *table2;
- } else if (colorTableIsIndexed(*table2)) {
- assertColorTableIsSorted(*table2);
- convertedTable = makeSequentialFromSortedIndexed(table2, fillColor);
- t1 = *table1;
- t2 = *convertedTable;
- }
-
- if ( (nEntriesMinusOne=t1->ctSize) != t2->ctSize) {
-
- areEquivalent = FALSE;
-
- } else {
-
- register short cEntry;
-
- for (cEntry = 0; cEntry <= nEntriesMinusOne; ++cEntry) {
-
- /*
- * When comparing sequential tables, ignore the value field.
- */
-
- if ( t1->ctTable[cEntry].rgb.red != t2->ctTable[cEntry].rgb.red
- || t1->ctTable[cEntry].rgb.green != t2->ctTable[cEntry].rgb.green
- || t1->ctTable[cEntry].rgb.blue != t2->ctTable[cEntry].rgb.blue ) {
-
- areEquivalent = FALSE;
- break;
-
- }
-
- }
-
- }
-
- DisposHandle( (Handle) convertedTable );
-
- } else {
-
- /*
- * Leave both tables indexed, and compare. Assume they're sorted.
- */
-
- register CTabPtr t1, t2;
- register short nEntriesMinusOne;
-
- t1 = *table1;
- t2 = *table2;
-
- assertColorTableIsSorted(t1);
- assertColorTableIsSorted(t2);
-
- if ( (nEntriesMinusOne=t1->ctSize) != t2->ctSize) {
-
- areEquivalent = FALSE;
-
- } else {
-
- register short cEntry;
-
- areEquivalent = ( jmemcmp( // jmemcmp() is just a memcmp() clone
- &t1->ctTable[0],
- &t2->ctTable[0],
- sizeof(ColorSpec)*(nEntriesMinusOne+1)
- ) == 0);
-
- #if you_want_it_spelled_out_for_you
- for (cEntry = 0; cEntry <= nEntriesMinusOne; ++cEntry) {
- if ( t1->ctTable[cEntry].value != t2->ctTable[cEntry].value
- || t1->ctTable[cEntry].rgb.red != t2->ctTable[cEntry].rgb.red
- || t1->ctTable[cEntry].rgb.green != t2->ctTable[cEntry].rgb.green
- || t1->ctTable[cEntry].rgb.blue != t2->ctTable[cEntry].rgb.blue ) {
- areEquivalent = FALSE;
- break;
- }
- }
- #endif
-
- }
-
- }
-
- return areEquivalent;
- }
-
-
-
- short (getNCTEntries)(CTabPtr theTable)
- {
- return theTable->ctSize + 1;
- }
-
-
-
- void setNCTEntries(CTabHandle theTable, short nEntries)
- {
- short oldState;
-
- ASSERT(nEntries >= 0);
- ASSERT(nEntries <= 256); // arbitrary
-
- if (getNCTEntries(*theTable) == nEntries) return;
-
- (**theTable).ctSize = nEntries-1;
-
- oldState = HGetState( (Handle) theTable );
- HUnlock( (Handle) theTable );
- SetHandleSize( (Handle) theTable,
- sizeof(ColorTable) + (nEntries-1)*sizeof(ColorSpec));
- HSetState( (Handle) theTable, oldState);
- }
-
-
-
- void changeNCTEntries(CTabHandle theTable, short nEntries)
- {
- if (nEntries == 0) return;
-
- setNCTEntries(theTable, getNCTEntries(*theTable) + nEntries);
- }
-
-
-
- void (convertDepthToMaxNEntries)(short d, short n)
- {
- DebugStr("\pconvertDepthToMaxNEntries was somehow called!");
- }
-
-
-
- void (convertNEntriesToMinDepth)(short n, short d)
- {
- DebugStr("\pconvertNEntriesToMinDepth was somehow called!");
- }
-
-