#include "opctool.h"
Go to the source code of this file.
Functions | |
void OPC_NAMING() | ShrinkBound (OPC *dst, const OPC *src, OPC_NAMING(Pixel) transparent) |
Find the non-transparent edges of a shape Copies src to dst, then moves clipping bounds of dst down until they all hit something non-transparent. | |
size_t OPC_NAMING() | Shape_Calc (const OPC *src, OPC_NAMING(Pixel) transparent, bool bMask) |
Calculate how big a buffer would be required to define a new shape This will usually calculate a little bigger, because it doesn't bother working out how to eliminate excess skips. | |
OPCShape *OPC_NAMING() | Shape_Create (const OPC *src, OPC_NAMING(Pixel) transparent, void *buffer, bool bMask) |
Define a new transparent shape Not super optimized, more a tool library or initialization function Origin is set to clipping box's origin, so make an OPC_Window, then find the edges, then pass that in. | |
size_t OPC_NAMING() | Shape_Pack_Needs (OPCShape *shape) |
Do something like LZ+RLE on non-transparent parts of a shape. | |
size_t OPC_NAMING() | Shape_Pack (OPCShape *shape, void *buffer) |
Do something like LZ on non-transparent, non-RUN parts of a shape. | |
void OPC_NAMING() | ExportH (const OPC *opc, FILE *fp, const char *szname) |
Export a header definition for OPC data. | |
void OPC_NAMING() | ExportC (const OPC *opc, FILE *fp, const char *modifier, const char *szname, const char *szComment,...) |
Export the OPC structure portion of OPC data. | |
void OPC_NAMING() | ExportCData (const OPC *opc, FILE *fp, const char *szname) |
Export the OPCShape pixel image data. | |
void OPC_NAMING() | Shape_ExportH (const OPCShape *shape, FILE *fp, const char *szname, bool bMask) |
Export a header definition for OPCShape data. | |
void OPC_NAMING() | Shape_ExportC (const OPCShape *shape, FILE *fp, const char *modifier, const char *szname, bool bMask, const char *szComment,...) |
Export the OPCShape structure portion of OPC data. | |
void OPC_NAMING() | Shape_ExportCData (const OPCShape *shape, FILE *fp, const char *szname, bool bMask) |
Export the OPCShape pixel image data. |
Definition in file opctool.temp.h.
void OPC_NAMING() ExportC | ( | const OPC * | opc, | |
FILE * | fp, | |||
const char * | modifier, | |||
const char * | szname, | |||
const char * | szComment, | |||
... | ||||
) |
Export the OPC structure portion of OPC data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
modifier | Definition modifier (such as 'static' or __declspec(dllexport)), or just "" | |
szname | What to call this particular export | |
szComment | An optional comment for the export, or NULL if you don't want it Writes OPC with forward references to static data |
Definition at line 538 of file opctool.temp.h.
00539 { 00540 if( szComment ) 00541 { 00542 va_list args; 00543 va_start( args, szComment ); /* Initialize variable arguments. */ 00544 fputs( "\n/*\n * ", fp ); 00545 vfprintf( fp, szComment, args ); 00546 fputs( "\n */\n", fp ); 00547 } 00548 fprintf( fp, "static const OPC_NAMING(Pixel) data_%s[];\n", szname ); 00549 if( modifier && *modifier ) 00550 fprintf( fp, "%s ", modifier ); 00551 fprintf( fp, "const OPC %s = /* Stamp */\n{\n", szname ); 00552 fprintf( fp, "\t(uint8*)data_%s,\t/* origin */\n", szname ); 00553 fprintf( fp, "\t%d,\t/* pitch */\n", abs(opc->pitch) ); 00554 fprintf( fp, "\t{%d,%d,%d,%d}\t/* clip */\n", opc->clip.left, opc->clip.top, opc->clip.right, opc->clip.bottom ); 00555 fputs( "};\n", fp ); 00556 }
void OPC_NAMING() ExportCData | ( | const OPC * | opc, | |
FILE * | fp, | |||
const char * | szname | |||
) |
Export the OPCShape pixel image data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
szname | What to call this particular export Writes the static data, tries to write it same shape as opc, but gives up past a certain point. |
Definition at line 572 of file opctool.temp.h.
References RectHigh, RectWide, throwassert, and wrap.
00573 { 00574 #ifndef GIVEUP_AFTER 00575 #define GIVEUP_AFTER 15 00576 #endif 00577 size_t curr; 00578 const OPC_NAMING(Pixel)* pData = (const OPC_NAMING(Pixel)*)opc->origin; 00579 size_t size = OPC_NAMING(Needs)( RectWide(opc->clip), RectHigh(opc->clip) ); 00580 unsigned wrap = min( RectWide(opc->clip), GIVEUP_AFTER ); 00581 fprintf( fp, "static const OPC_NAMING(Pixel) data_%s[%d] = \n{\n\t", szname, size ); 00582 #ifdef PIXEL_OUTPUT 00583 for( curr = 0; curr < size; ++curr ) 00584 { 00585 PIXEL_OUTPUT( fp, *pData++ ); 00586 if( (curr % wrap) == wrap - 1 ) 00587 fputs( "\n\t", fp ); 00588 } 00589 #else 00590 switch(sizeof(OPC_NAMING(Pixel))) 00591 { 00592 case 1: 00593 for( curr = 0; curr < size; ++curr ) 00594 { 00595 fprintf( fp, "%3d,", (unsigned)*pData++ ); 00596 if( (curr % wrap) == wrap - 1 ) 00597 fputs( "\n\t", fp ); 00598 } 00599 break; 00600 case 2: 00601 for( curr = 0; curr < size; ++curr ) 00602 { 00603 fprintf( fp, "0x%04x,", (unsigned)*pData++ ); 00604 if( (curr % wrap) == wrap - 1 ) 00605 fputs( "\n\t", fp ); 00606 } 00607 break; 00608 case 4: 00609 for( curr = 0; curr < size; ++curr ) 00610 { 00611 fprintf( fp, "0x%08x,", (unsigned)*pData++ ); 00612 if( (curr % wrap) == wrap - 1 ) 00613 fputs( "\n\t", fp ); 00614 } 00615 break; 00616 case 8: 00617 for( curr = 0; curr < size; ++curr ) 00618 { 00619 fprintf( fp, "0x%" LLX(char) ",", (uint64)*pData++ ); 00620 if( (curr % wrap) == wrap - 1 ) 00621 fputs( "\n\t", fp ); 00622 } 00623 break; 00624 default: 00625 throwassert( "Invalid pixel size." ); 00626 break; 00627 } 00628 fputs( "\n};\n", fp ); 00629 #endif 00630 }
void OPC_NAMING() ExportH | ( | const OPC * | opc, | |
FILE * | fp, | |||
const char * | szname | |||
) |
Export a header definition for OPC data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
szname | What to call this particular export |
Definition at line 521 of file opctool.temp.h.
References RectHigh, and RectWide.
00522 { 00523 fprintf( fp, "#define %s_BOUND(x,y)\t{(x),(y),(x)+%d,(y)+%d}\n", szname, RectWide(opc->clip), RectHigh(opc->clip) ); 00524 fprintf( fp, "#define %s_WIDE\t%d\n", szname, RectWide(opc->clip) ); 00525 fprintf( fp, "#define %s_HIGh\t%d\n", szname, RectHigh(opc->clip) ); 00526 fprintf( fp, "extern const OPC %s; /* Stamp */\n", szname ); 00527 }
size_t OPC_NAMING() Shape_Calc | ( | const OPC * | src, | |
OPC_NAMING(Pixel) | transparent, | |||
bool | bMask | |||
) |
Calculate how big a buffer would be required to define a new shape This will usually calculate a little bigger, because it doesn't bother working out how to eliminate excess skips.
src | OPC containing shape to be defined | |
transparent | Color to consider 'invisible' | |
bMask | True if we're making a mask, rather than a textured shape |
Definition at line 117 of file opctool.temp.h.
References Rect::bottom, Rect::left, Rect::right, and Rect::top.
00118 { 00119 size_t dataLen = 0; 00120 size_t codeLen = 0; 00121 int x, y; 00122 for( y = src->clip.top; y < src->clip.bottom; ++y ) 00123 { 00124 for( x = src->clip.left; x < src->clip.right; ) 00125 { 00126 { 00127 const OPC_NAMING(Pixel)* line = OPC_PTR( src, x,y ); 00128 int skip = 0; 00129 for( ; x < src->clip.right && skip < MAX_SKIP && *line++ == transparent; x++ ) 00130 skip++; 00131 if( skip ) 00132 { 00133 codeLen++; 00134 } 00135 } 00136 { 00137 const OPC_NAMING(Pixel)* line = OPC_PTR( src, x,y ); 00138 int run = 0; 00139 for( ; x < src->clip.right && run < MAX_DUMP && *line++ != transparent; x++ ) 00140 run++; 00141 if( run ) 00142 { 00143 codeLen++; 00144 if( !bMask ) 00145 dataLen+=run; 00146 } 00147 } 00148 } 00149 codeLen++; 00150 } 00151 codeLen++; 00152 return sizeof(OPCShape) + (codeLen+sizeof(int)) + (dataLen * sizeof(OPC_NAMING(Pixel))); 00153 }
OPCShape* OPC_NAMING() Shape_Create | ( | const OPC * | src, | |
OPC_NAMING(Pixel) | transparent, | |||
void * | buffer, | |||
bool | bMask | |||
) |
Define a new transparent shape Not super optimized, more a tool library or initialization function Origin is set to clipping box's origin, so make an OPC_Window, then find the edges, then pass that in.
src | OPC containing shape to be defined | |
transparent | Color to consider 'invisible' | |
buffer | A buffer of at least OPC_CalcShape(src,transparent) bytes to convert into | |
bMask | True if we're making a mask, rather than a textured shape |
Codes (signed char code array): -1~-127 Skip -128: End line 0: End shape 1~MAX_DUMP: Copy MAX_DUMP~127: Fill If 'code' is not NULL, and first 'code' is 0, data is packed somehow
The pixel data can be either just dumped, or further compressed.
The compression to apply has a LOT to do with the target format and speed of target system. For instance, a PC will handle full-blown LZH compression, but many embedded CPUs will not. RLE might do very nicely on data with lots of solid runs, and a target with little or no horsepower to use on decompressing data. Data alignment also figures into the problem since data on 32 bit boundaries will consume 32 bits for a code, even if the code is 8-bits.
Definition at line 188 of file opctool.temp.h.
References Rect::bottom, OPC::clip, OPCShape::code, OPCShape::data, OPCShape::high, Rect::left, OPCShape::pack, OPC::pitch, RectHigh, RectWide, Rect::right, ShrinkBound(), Rect::top, OPCShape::wide, OPCShape::xOff, and OPCShape::yOff.
00189 { 00190 OPC bound; 00191 OPCShape* shape = (OPCShape*)buffer; 00192 int8* pCode = (int8*)(shape+1); 00193 int x, y; 00194 OPC_NAMING(ShrinkBound)( &bound, src, transparent ); 00195 #ifdef OPC_POINTERS 00196 shape->code = pCode; 00197 shape->data = NULL; 00198 shape->pack = NULL; 00199 #else 00200 shape->code = pCode-(int8*)shape; 00201 shape->data = 0; 00202 shape->pack = 0; 00203 #endif 00204 shape->wide = (uint16)RectWide(bound.clip); 00205 shape->high = (uint16)RectHigh(bound.clip); 00206 shape->xOff = (int16)bound.clip.left; 00207 shape->yOff = (int16)bound.clip.top; 00208 for( y = bound.clip.top; y < bound.clip.bottom; ++y ) 00209 { 00210 for( x = bound.clip.left; x < bound.clip.right; ) 00211 { 00212 { 00213 /* Skip transparent */ 00214 const OPC_NAMING(Pixel)* line = OPC_PTR( src, x,y ); 00215 int skip = 0; 00216 for( x = x; x < bound.clip.right && skip < MAX_SKIP && *line == transparent; x++, skip++, line++ ) 00217 ; 00218 if( skip ) 00219 { 00220 *pCode++ = SKIP_CODE(skip); 00221 continue; 00222 } 00223 } 00224 { 00225 /* Now do RLE on non-transparent pixels */ 00226 const OPC_NAMING(Pixel)* line = OPC_PTR( src, x,y ); 00227 int dump = 0; 00228 for( x = x; x < bound.clip.right && dump < MAX_DUMP && *line != transparent; x++, dump++, line++ ) /* Small optimization for 8/16 bit data on large, solid shapes */ 00229 if( !bMask ) /* If we're building a mask, we don't need to break lines down */ 00230 { 00231 /* Look for runs of color in dump */ 00232 PIXEL prun = *line; 00233 const PIXEL* scanLine = line+1; 00234 int run = 1; 00235 int tmpx; 00236 for( tmpx = x+1; tmpx < bound.clip.right && run < MAX_RUN && *scanLine == prun && *scanLine != transparent; tmpx++, run++, scanLine++ ) 00237 ; 00238 if( run >= MIN_RUN ) /* We want more than mere crumbs of run */ 00239 { 00240 /* Output dump code */ 00241 if( dump ) 00242 { 00243 *pCode++ = DUMP_CODE(dump); 00244 dump = 0; 00245 } 00246 /* Output run length */ 00247 *pCode++ = RUN_CODE(run); 00248 x = tmpx; 00249 break; 00250 } 00251 } 00252 if( dump ) 00253 { 00254 *pCode++ = DUMP_CODE(dump); 00255 } 00256 } 00257 } 00258 /* Consume any trailing skips (a wide shape might contain two or more skips on the trailing edge of the line) */ 00259 if( *(pCode-1) < 0 && *(pCode-1) != -128 && pCode > (int8*)(shape+1) ) 00260 *--pCode = -128; 00261 *pCode++ = -128; 00262 } 00263 /* Terminate, removing all trailing skips */ 00264 while( *(pCode-1) < 0 && pCode > (int8*)(shape+1) ) 00265 --pCode; 00266 *pCode++ = 0; 00267 /* Clear extra bytes & align 'pointer' */ 00268 while( (size_t)pCode & 3 ) 00269 *pCode++ = 0; 00270 if( bMask ) 00271 { 00272 shape->data = 0; 00273 } 00274 else 00275 { 00276 /* Get pixel data onto integer boundary */ 00277 #ifdef OPC_POINTERS 00278 shape->data = pCode; 00279 #else 00280 shape->data = pCode-(int8*)shape; 00281 #endif 00282 { 00283 /* 00284 * Now that we know how big the code is, we can copy the data onto the 00285 * end of it. Use the rle code we generated to determine what to copy 00286 */ 00287 #ifdef OPC_POINTERS 00288 const int8* pCode = shape->code; 00289 OPC_NAMING(Pixel)* pData = (OPC_NAMING(Pixel)*)shape->data; 00290 #else 00291 const int8* pCode = (int8*)shape + shape->code; 00292 OPC_NAMING(Pixel)* pData = (OPC_NAMING(Pixel)*)((uint8*)shape + shape->data); 00293 #endif 00294 const OPC_NAMING(Pixel)* pSrc = OPC_PTR( src, bound.clip.left,bound.clip.top ); 00295 const OPC_NAMING(Pixel)* pSpan = pSrc; 00296 size_t wrote = 0; 00297 for( ; ; ) 00298 { 00299 int curr = *pCode++; 00300 if( IS_SKIP(curr) ) 00301 { 00302 if( IS_EOL(curr) ) 00303 pSpan = pSrc = (OPC_NAMING(Pixel)*)((uint8*)pSrc + bound.pitch); 00304 else 00305 pSpan += SKIP_LEN(curr); 00306 } 00307 else if( IS_RUNDUMP(curr) ) 00308 { 00309 if( IS_RUN(curr) ) 00310 { 00311 OPC_HCOPY(pData,pSpan,1); 00312 pSpan += RUN_LEN(curr); 00313 pData += 1; 00314 wrote += sizeof(OPC_NAMING(Pixel)); 00315 } 00316 else /* if( IS_DUMP(curr) ) */ 00317 { 00318 OPC_HCOPY(pData,pSpan,curr); 00319 pSpan += DUMP_LEN(curr); 00320 pData += DUMP_LEN(curr); 00321 wrote += DUMP_LEN(curr) * sizeof(OPC_NAMING(Pixel)); 00322 } 00323 } 00324 else 00325 { 00326 break; 00327 } 00328 } 00329 if( !wrote ) 00330 shape->data = 0; 00331 } 00332 /* Now we know how big the whole thing is. */ 00333 /*shape->size = (uint8*)pData - (uint8*)shape;*/ 00334 } 00335 return shape; 00336 }
void OPC_NAMING() Shape_ExportC | ( | const OPCShape * | shape, | |
FILE * | fp, | |||
const char * | modifier, | |||
const char * | szname, | |||
bool | bMask, | |||
const char * | szComment, | |||
... | ||||
) |
Export the OPCShape structure portion of OPC data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
modifier | Definition modifier (such as 'static' or __declspec(dllexport)), or just "" | |
szname | What to call this particular export | |
bMask | If true, PIXEL data is exclued; just the OPCShape and runs | |
szComment | An optional comment for the export, or NULL if you don't want it Writes OPCShape structure with forward references to static data |
Definition at line 657 of file opctool.temp.h.
00658 { 00659 if( szComment ) 00660 { 00661 va_list args; 00662 va_start( args, szComment ); /* Initialize variable arguments. */ 00663 fputs( "\n/*\n * ", fp ); 00664 vfprintf( fp, szComment, args ); 00665 fputs( "\n */\n", fp ); 00666 } 00667 fprintf( fp, "static const int8 code_%s[%u];\n", szname, OPC_NAMING(Shape_CodeSize)( shape ) ); 00668 if( !bMask && shape->data ) 00669 fprintf( fp, "static const OPC_NAMING(Pixel) data_%s[%u];\n", szname, OPC_NAMING(Shape_DataSize)( shape ) ); 00670 if( !bMask && shape->pack ) 00671 fprintf( fp, "static const opc_pack_type pack_%s[%u];\n", szname, OPC_NAMING(Shape_PackLutSize)( shape ) ); 00672 if( modifier && *modifier ) 00673 fprintf( fp, "%s ", modifier ); 00674 fprintf( fp, "const OPCShape %s =\n", szname ); 00675 fputs( "{\n", fp ); 00676 fprintf( fp, "\t%3d,\t/* xOff */\n", shape->xOff ); 00677 fprintf( fp, "\t%3d,\t/* yOff */\n", shape->yOff ); 00678 fprintf( fp, "\t%3u,\t/* wide */\n", shape->wide ); 00679 fprintf( fp, "\t%3u,\t/* high */\n", shape->high ); 00680 fprintf( fp, "\tcode_%s,\t/* code */\n", szname ); 00681 if( bMask || !shape->data ) 00682 fprintf( fp, "\tNULL,\t/* no data */\n" ); 00683 else 00684 fprintf( fp, "\tdata_%s,\t/* data */\n", szname ); 00685 if( bMask || !shape->pack ) 00686 fprintf( fp, "\tNULL,\t/* no pack */\n" ); 00687 else 00688 fprintf( fp, "\tpack_%s,\t/* packed */\n", szname ); 00689 fputs( "};\n", fp ); 00690 }
void OPC_NAMING() Shape_ExportCData | ( | const OPCShape * | shape, | |
FILE * | fp, | |||
const char * | szname, | |||
bool | bMask | |||
) |
Export the OPCShape pixel image data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
szname | What to call this particular export Writes the static data, tries to write it same shape as opc | |
bMask | If true, PIXEL data is exclued; just the OPCShape and runs |
Definition at line 700 of file opctool.temp.h.
References throwassert.
00701 { 00702 size_t cCode = OPC_NAMING(Shape_CodeSize)( shape ); 00703 size_t curr; 00704 #ifdef OPC_POINTERS 00705 const int8* pCode = shape->code; 00706 #else 00707 const int8* pCode = (int8*)shape + shape->code; 00708 #endif 00709 /* Lay out codes intelligibly */ 00710 fprintf( fp, "static const int8 code_%s[%u] = \n{\n\t", szname, cCode ); 00711 for( curr = 0; curr < cCode; ++curr ) 00712 { 00713 int code = *pCode++; 00714 if( code == -128 ) 00715 { 00716 fputs( "-128,\n\t", fp ); 00717 } 00718 else 00719 { 00720 fprintf( fp, "%d, ", code ); 00721 } 00722 } 00723 fputs( "\n};\n", fp ); 00724 if( !bMask && shape->pack ) 00725 { 00726 size_t cData = OPC_NAMING(Shape_PackLutSize)( shape ); 00727 size_t cols = 0; 00728 #ifdef OPC_POINTERS 00729 const uint8* plut = (const opc_pack_type*)shape->pack; 00730 #else 00731 const uint8* plut = (const opc_pack_type*)shape + shape->pack; 00732 #endif 00733 /* Align data so a few more 32 bit DMA's can happen on 8/16 bit art */ 00734 fprintf( fp, "static const OPC_NAMING(Pixel) pack_%s[%u] __attribute__((aligned)) = \n{\n\t", szname, cData ); 00735 while( cData-- ) 00736 { 00737 fprintf( fp, "%d,", (unsigned)*plut++ ); 00738 ++cols; 00739 if( 0 == (cols & 0xf) ) 00740 { 00741 fputs( "\n\t", fp ); 00742 cols = 0; 00743 } 00744 } 00745 fputs( "\n};\n", fp ); 00746 } 00747 if( !bMask && shape->data ) 00748 { 00749 /* Draw shapes recognizably */ 00750 size_t cData = OPC_NAMING(Shape_DataSize)( shape ); 00751 size_t cols = 0; 00752 #ifdef OPC_POINTERS 00753 const uint8* pData = (const uint8*)shape->data; 00754 #else 00755 const uint8* pData = (const uint8*)shape + shape->data; 00756 #endif 00757 /* Align data so a few more 32 bit DMA's can happen on 8/16 bit art */ 00758 fprintf( fp, "static const OPC_NAMING(Pixel) data_%s[%u] __attribute__((aligned)) = \n{\n\t", szname, cData ); 00759 while( cData-- ) 00760 { 00761 #ifdef PIXEL_OUTPUT 00762 PIXEL_OUTPUT( fp, *pData++ ); 00763 #else 00764 switch(sizeof(OPC_NAMING(Pixel))) 00765 { 00766 case 1: 00767 fprintf( fp, "0x%02x,", (unsigned)*pData++ ); 00768 break; 00769 case 2: 00770 fprintf( fp, "0x%04x,", (unsigned)*pData++ ); 00771 break; 00772 case 4: 00773 fprintf( fp, "0x%08x,", (unsigned)*pData++ ); 00774 break; 00775 case 8: 00776 fprintf( fp, "0x%" LLX(char) ",", (uint64)*pData++ ); 00777 break; 00778 default: 00779 throwassert( "Invalid pixel size." ); 00780 break; 00781 } 00782 #endif 00783 ++cols; 00784 if( 0 == (cols & 0xf) ) 00785 { 00786 fputs( "\n\t", fp ); 00787 cols = 0; 00788 } 00789 else if( 0 == (cols & 7) ) 00790 { 00791 fputs( " ", fp ); 00792 } 00793 } 00794 fputs( "\n};\n", fp ); 00795 } 00796 }
void OPC_NAMING() Shape_ExportH | ( | const OPCShape * | shape, | |
FILE * | fp, | |||
const char * | szname, | |||
bool | bMask | |||
) |
Export a header definition for OPCShape data.
opc | Solid buffer we're weiting | |
fp | FILE* open to write to a header file | |
szname | What to call this particular export | |
bMask | If true, PIXEL data is exclued; just the OPCShape and runs |
Definition at line 639 of file opctool.temp.h.
00640 { 00641 fprintf( fp, "#define %s_BOUND(x,y)\t{ (x)+%d, (y)+%d, (x)+%d+%d, (y)+%d+%d }\n", szname, shape->xOff, shape->yOff, shape->xOff, shape->xOff+shape->wide, shape->yOff, shape->yOff + shape->high ); 00642 fprintf( fp, "#define %s_WIDE\t%d\n", szname, shape->wide ); 00643 fprintf( fp, "#define %s_HIGH\t%d\n", szname, shape->high ); 00644 fprintf( fp, "extern const OPCShape %s;\n", szname ); 00645 }
size_t OPC_NAMING() Shape_Pack | ( | OPCShape * | shape, | |
void * | buffer | |||
) |
Do something like LZ on non-transparent, non-RUN parts of a shape.
shape | Shape to attempt compression on | |
buffer | Scratch buffer, needs at least 'OPC_NAMING(Shape_Pack_Needs)(shape)' bytes |
All in all, this doesn't try very hard to find runs. It only searches for matches the same size as the RLE dumps that are passed in. Otherwise, clipping could get really ugly and time-consuming. The idea here is to have some compression, but not make it really cost us anything substantial in runtime cycles, possibly saving some runtime cycles on cache hits. It's also important to me to keep the RLE compression seperate from this packing, so 'better' and more time- consuming packing can be added for faster target platforms without melting down the whole skip compressed format.
TODO: I need to rethink this kludged format a bit; the source code output is endian-dependant; tool and code must match for source to work. It's that uint16 LUT.
Definition at line 373 of file opctool.temp.h.
References assert.
00374 { 00375 #ifdef OPC_POINTERS 00376 int8* pCode = shape->code; 00377 OPC_NAMING(Pixel)* pData = (OPC_NAMING(Pixel)*)shape->data; 00378 #else 00379 int8* pCode = (int8*)shape + shape->code; 00380 OPC_NAMING(Pixel)* pData = (OPC_NAMING(Pixel)*)((uint8*)shape + shape->data); 00381 #endif 00382 if( pData && !shape->pack ) 00383 { 00384 /* 00385 * Go through the shape run-by-run, and see if any runs can be 00386 * made from earlier data, or if runs are just a solid fill-color. 00387 * 00388 * Unsigned 16 bit window 00389 * >0: Lookup pixels from earlier spans (length from 'pCode') 00390 * 0: Start from current position 00391 * 00392 * Special case: a run may be added to from '-code' that is 00393 * shorter than 'span', if the additional bytes are added after 00394 * it. For instance, a previous span ended '...21234', and the 00395 * current one is '23456...,' the '234' can be used for the 00396 * current span, only adding '56...' on the end. This will help 00397 * with some pattern fills that might not have compressed at all. 00398 * 00399 */ 00400 opc_pack_type* pIndexBegin = (opc_pack_type*)(buffer); 00401 opc_pack_type* pIndexEnd = pIndexBegin; 00402 opc_pack_type* pIndexes = pIndexBegin; 00403 const int8* pCodeEnd, *pCodeBegin; 00404 int indexCount = 0; 00405 OPC_NAMING(Pixel)* pixBegin, *pixCurr; 00406 OPC_NAMING(Pixel)* pixEnd = (uint8*)buffer + OPC_NAMING(Shape_DataSize)( shape ); 00407 { 00408 pCodeBegin = pCodeEnd = pCode; 00409 while( *pCodeEnd ) 00410 { 00411 int code = *pCodeEnd++; 00412 if( IS_DUMP(code) ) 00413 indexCount++; 00414 } 00415 pIndexEnd = pIndexBegin + indexCount; 00416 while( (size_t)pIndexEnd & 3 ) 00417 { 00418 pIndexEnd++; 00419 } 00420 pixBegin = pixCurr = (OPC_NAMING(Pixel)*)pIndexEnd; 00421 } 00422 while( pixCurr < pixEnd ) 00423 { 00424 int code = *pCode++; 00425 if( IS_RUN(code) ) 00426 { 00427 /* 00428 * Runs of color are transferred without an index lookup 00429 */ 00430 /* Don't smash RAM */ 00431 if( pixCurr + 1 > pixEnd ) 00432 break; 00433 *pixCurr++ = *pData++; 00434 } 00435 else if( IS_DUMP(code) ) 00436 { 00437 assert( pCode <= pCodeEnd ); 00438 assert( pIndexes < (opc_pack_type*)pixBegin ); 00439 /* See if some of new run can be re-used from previous run */ 00440 { 00441 int best = 0; 00442 int bestLen = 0; 00443 int index = 0; 00444 const OPC_NAMING(Pixel)* scan = pixCurr; 00445 while( scan-- > pixBegin && ++index < opc_pack_max ) 00446 { 00447 size_t scanLen = min(pixCurr-scan,code); 00448 if( !memcmp(scan,pData,sizeof(OPC_NAMING(Pixel))*scanLen) ) 00449 { 00450 best = index; 00451 bestLen = scanLen; 00452 /* If we found a match equal to full code size, mission accomplished */ 00453 if( bestLen == code ) 00454 break; 00455 } 00456 } 00457 if( bestLen > 0 ) 00458 { 00459 *pIndexes++ = best; 00460 if( bestLen < code ) 00461 { 00462 /* Don't smash RAM */ 00463 if( pixCurr + (code-bestLen) > pixEnd ) 00464 break; 00465 memcpy( pixCurr, pData+best, sizeof(OPC_NAMING(Pixel))*(code-bestLen) ); 00466 pixCurr += (code-bestLen); 00467 } 00468 pData += code; 00469 continue; 00470 } 00471 } 00472 /* Just dump new run on end and hope future runs are better */ 00473 { 00474 /* Don't smash RAM */ 00475 if( pixCurr + code > pixEnd ) 00476 break; 00477 *pIndexes++ = 0; 00478 memcpy( pixCurr, pData, sizeof(OPC_NAMING(Pixel))*code ); 00479 pixCurr += code; 00480 pData += code; 00481 } 00482 } 00483 else if( code == 0 ) 00484 { 00485 /* 00486 * We hit the end and didn't run out? SUCCESS! 00487 * Update OPCShape, copy new data, etc. 00488 */ 00489 size_t packsize = (size_t)pixCurr - (size_t)buffer; 00490 00491 /* Clear extra bytes & align pointer */ 00492 while( (size_t)pCode & 3 ) 00493 *pCode++ = 0; 00494 memcpy( pCode, buffer, packsize ); 00495 00496 #ifdef OPC_POINTERS 00497 shape->pack = pCode; 00498 shape->data = pCode + (pIndexEnd-pIndexBegin); 00499 #else 00500 shape->pack = (size_t)pCode - (size_t)shape; 00501 shape->data = shape->pack + (pIndexEnd-pIndexBegin); 00502 #endif 00503 00504 return OPC_NAMING(Shape_TotalSize)( shape ); 00505 } 00506 /* else if( code < 0 ), we ignore it. */ 00507 } 00508 } 00509 /* 00510 * Just return input shape's size 00511 */ 00512 return OPC_NAMING(Shape_TotalSize)( shape ); 00513 }
Find the non-transparent edges of a shape Copies src to dst, then moves clipping bounds of dst down until they all hit something non-transparent.
dst | OPC we're constructing from src. | |
src | OPC we're making a shrunken version of | |
transparent | Pixel value to treat as transparent |
Definition at line 35 of file opctool.temp.h.
References Rect::bottom, and Rect::right.
Referenced by Shape_Create().
00036 { 00037 if( dst != src ) 00038 *dst = *src; 00039 /* Move down top edge until it hits something */ 00040 while( dst->clip.top < dst->clip.bottom ) 00041 { 00042 OPC_NAMING(Pixel) pixel = transparent; 00043 const OPC_NAMING(Pixel)* curr = OPC_PTR( dst, dst->clip.left,dst->clip.top ); 00044 int x; 00045 for( x = dst->clip.left; x < dst->clip.right; ++x ) 00046 { 00047 pixel = *curr++; 00048 if( pixel != transparent ) 00049 break; 00050 } 00051 if( pixel != transparent ) 00052 break; 00053 dst->clip.top++; 00054 } 00055 /* Move up bottom edge until it hits something */ 00056 while( dst->clip.top < dst->clip.bottom ) 00057 { 00058 OPC_NAMING(Pixel) pixel = transparent; 00059 const OPC_NAMING(Pixel)* curr = OPC_PTR( dst, dst->clip.left,dst->clip.bottom-1 ); 00060 int x; 00061 for( x = dst->clip.left; x < dst->clip.right; ++x ) 00062 { 00063 pixel = *curr++; 00064 if( pixel != transparent ) 00065 break; 00066 } 00067 if( pixel != transparent ) 00068 break; 00069 dst->clip.bottom--; 00070 } 00071 /* Move left edge right until it hits something */ 00072 while( dst->clip.left < dst->clip.right ) 00073 { 00074 OPC_NAMING(Pixel) pixel = transparent; 00075 const OPC_NAMING(Pixel)* curr = OPC_PTR( dst, dst->clip.left,dst->clip.top ); 00076 int pitch = dst->pitch; 00077 int y; 00078 for( y = dst->clip.top; y < dst->clip.bottom; ++y ) 00079 { 00080 pixel = *curr; 00081 curr = (OPC_NAMING(Pixel)*)((uint8*)curr + pitch); 00082 if( pixel != transparent ) 00083 break; 00084 } 00085 if( pixel != transparent ) 00086 break; 00087 dst->clip.left++; 00088 } 00089 /* Move right edge left until it hits something */ 00090 while( dst->clip.left < dst->clip.right ) 00091 { 00092 OPC_NAMING(Pixel) pixel = transparent; 00093 const OPC_NAMING(Pixel)* curr = OPC_PTR( dst, dst->clip.right-1,dst->clip.top ); 00094 int pitch = dst->pitch; 00095 int y; 00096 for( y = dst->clip.top; y < dst->clip.bottom; ++y ) 00097 { 00098 pixel = *curr; 00099 curr = (OPC_NAMING(Pixel)*)((uint8*)curr + pitch); 00100 if( pixel != transparent ) 00101 break; 00102 } 00103 if( pixel != transparent ) 00104 break; 00105 dst->clip.right--; 00106 } 00107 }