/*
Copyright (C) 2013 by Brendan G Bohannon
Email: cr88192@gmail.com
Copying: http://pastebin.com/iJxtZHm6
*/
/*
DXTn packed images.
Each block tag will be encoded in the form (byte):
0 <block:QWORD> Literal Block.
1-127 Single byte block index.
128-191 X Two byte block index (16384 blocks).
192-223 XX Three byte block index (2097152 blocks).
224-238 I LZ/RLE Run (2-16 blocks, Index)
239 LI LZ/RLE Run (Length, Index)
240 XXX 24-Bit Index
241 XXXX 32-Bit Index
242-246 Literal Blocks (2-6 Blocks)
247 L Literal Blocks (L Blocks)
248-255 Reserved
The block index will indicate how many blocks backwards to look for a matching block (1 will repeat the prior block).
Length/Index values will use the same organization as above, only limited to encoding numeric values.
0-127 0-127.
128-191 X 128-16383.
192-223 XX 16384-2097151.
240 XXX 24-Bit Index (0-16777215)
241 XXXX 32-Bit Index (0-4294967295)
Note that DXT5 images will be split into 2 block-planes, with the first encoding the alpha component, followed by the plane encoding the RGB components.
*/
byte *BGBBTJ_PackBCn_DecodeValue(byte *cs, int *rval)
{
int op, i;
op=*cs++;
if(op<128)
{ *rval=op; return(cs); }
if(op<192)
{
*rval=((op-128)<<8)|(*cs++);
return(cs);
}
if(op<224)
{
i=((op-192)<<8)|(*cs++);
i=(i<<8)|(*cs++);
*rval=i;
return(cs);
}
if(op==240)
{
i=*cs++;
i=(i<<8)|(*cs++);
i=(i<<8)|(*cs++);
*rval=i;
return(cs);
}
if(op==241)
{
i=*cs++; i=(i<<8)|(*cs++);
i=(i<<8)|(*cs++); i=(i<<8)|(*cs++);
*rval=i;
return(cs);
}
return(cs);
}
byte *BGBBTJ_PackBCn_DecodeRun(byte *cs, int *ridx, int *rlen)
{
int op, i;
op=*cs++;
if(!op)
{ *ridx=0; *rlen=0; return(cs); }
if(op<128)
{ *ridx=op; *rlen=1; return(cs); }
if(op<192)
{
*ridx=((op-128)<<8)|(*cs++);
*rlen=1;
return(cs);
}
if(op<224)
{
i=((op-192)<<8)|(*cs++);
i=(i<<8)|(*cs++);
*ridx=i;
*rlen=1;
return(cs);
}
if(op<239)
{
cs=BGBBTJ_PackBCn_DecodeValue(cs, ridx);
*rlen=(op-224)+2;
return(cs);
}
if(op==239)
{
cs=BGBBTJ_PackBCn_DecodeValue(cs, rlen);
cs=BGBBTJ_PackBCn_DecodeValue(cs, ridx);
return(cs);
}
if(op==240)
{
i=*cs++;
i=(i<<8)|(*cs++);
i=(i<<8)|(*cs++);
*ridx=i;
*rlen=1;
return(cs);
}
if(op==241)
{
i=*cs++; i=(i<<8)|(*cs++);
i=(i<<8)|(*cs++); i=(i<<8)|(*cs++);
*ridx=i;
*rlen=1;
return(cs);
}
if(op<247)
{
*ridx=0;
*rlen=(op-242)+2;
return(cs);
}
if(op==247)
{
*ridx=0;
cs=BGBBTJ_PackBCn_DecodeValue(cs, rlen);
return(cs);
}
*ridx=0; *rlen=0;
return(cs);
}
byte *BGBBTJ_PackBCn_DecodeBlockArray(byte *ibuf, byte *blks,
int count, int stride)
{
byte *cs, *ct, *cte, *cs1, *ct1, *cs1e;
int bi, bl;
int i, j;
cs=ibuf; ct=blks; cte=ct+count*stride;
while(ct<cte)
{
cs=BGBBTJ_PackBCn_DecodeRun(cs, &bi, &bl);
if(bi==0)
{
if(bl>1)
{
#if defined(X86) || defined(X86_64)
cs1e=cs+bl*8;
while(cs<cs1e)
{
*(u64 *)ct=*(u64 *)(cs);
cs+=8; ct+=stride;
}
#else
for(i=0; i<bl; i++)
{ memcpy(ct+i*stride, cs+i*8, 8); }
cs+=bl*8;
ct+=bl*stride;
#endif
continue;
}
#if defined(X86) || defined(X86_64)
*(u64 *)ct=*(u64 *)cs;
#else
memcpy(ct, cs, 8);
#endif
ct+=stride; cs+=8;
continue;
}
#if defined(X86) || defined(X86_64)
cs1=ct-bi*stride;
cs1e=cs1+bl*stride;
while(cs1<cs1e)
{
*(u64 *)ct=*(u64 *)(cs1);
cs1+=stride; ct+=stride;
}
#else
for(i=0; i<bl; i++)
{ memcpy(ct+i*stride, ct+(i-bi)*stride, 8); }
ct+=bl*stride;
#endif
}
return(cs);
}
BGBBTJ_API int BGBBTJ_PackBCn_DecodeBlocksDXT5(
byte *ibuf, byte *blks, int count)
{
byte *cs;
cs=BGBBTJ_PackBCn_DecodeBlockArray(ibuf, blks, count, 16);
cs=BGBBTJ_PackBCn_DecodeBlockArray(cs, blks+8, count, 16);
return(cs-ibuf);
}