FSPDS/arm9/source/frame_decoder.cpp
2023-06-22 15:10:46 +03:00

222 lines
4.2 KiB
C++

#include "frame_decoder.hpp"
#include "chunks_bin.h"
#include "DSC"
int* chunks32 = (int*)chunks_bin;
void lsh_nibbles(int* buff, int cnt, int shift_pos, int* dest)
{
int off = shift_pos/8;
shift_pos=(shift_pos&7)*4;
buff+=off;
cnt-=off;
unsigned int v=*(buff++);
*dest = v>>shift_pos;
for(;cnt>1;cnt--)
{
v=*(buff++);
*(dest++) |= (v&((1<<shift_pos)-1))<<(32-shift_pos);
*dest = v>>shift_pos;
}
//v=*(buff++);
//*(dest++) |= (v&((1<<shift_pos)-1))<<(32-shift_pos);
for(;off--;*(dest++) = 0);
}
void rsh_nibbles(int* buff, int cnt, int shift_pos, int* dest)
{
int off = shift_pos/8;
shift_pos=(shift_pos&7)*4;
dest+=cnt;
cnt-=off;
buff+=cnt;
unsigned int v=*(--buff);
*(--dest)= v<<shift_pos;
for(;cnt>1;cnt--)
{
v=*(--buff);
*(dest)|=(v>>(32-shift_pos));
*(--dest) = v<<shift_pos;
}
for(;off--;*(--dest) = 0);
}
char* typed_decode(char* linedata, char* encoded, int* dest)
{
for(int cnt=48;cnt--;)
{
unsigned char byte = *(linedata++);
for(int q=4;q--;)
{
int enc_type = byte&3;
byte>>=2;
switch(enc_type)
{
case 0:
for(int i=32;i--;) *(dest++)=0;
break;
case 1:
case 2:
{
int default_value = enc_type==1 ? 0x00000000 : 0x11111111;
unsigned int chunk_flags=encoded[3]+(encoded[2]<<8)+(encoded[1]<<16)+(encoded[0]<<24);
encoded+=4;
//while(chunk_flags)
for(int i=32;i--;)
{
*(dest++) = (chunk_flags & 0x80000000) ? chunks32[(unsigned int)*(encoded++)] : default_value;
chunk_flags <<= 1;
}
break;
}
case 3:
for(int i=32;i--;)
{
*(dest++)=chunks32[*(encoded++)];
}
break;
}
}
}
//DSC::Debug::log("New encoded = %X", encoded);
return encoded;
}
char* typed_decode_xor(char* linedata, char* encoded, int* dest)
{
for(int cnt=48;cnt--;)
{
unsigned char byte = *(linedata++);
for(int q=4;q--;)
{
int enc_type = byte&3;
byte>>=2;
switch(enc_type)
{
case 0:
dest+=32;
break;
case 1:
case 2:
{
int default_value = enc_type==1 ? 0x00000000 : 0x11111111;
unsigned int chunk_flags=encoded[3]+(encoded[2]<<8)+(encoded[1]<<16)+(encoded[0]<<24);
encoded+=4;
//while(chunk_flags)
for(int i=32;i--;)
{
*(dest++) ^= (chunk_flags & 0x80000000) ? chunks32[(unsigned int)*(encoded++)] : default_value;
chunk_flags <<= 1;
}
break;
}
case 3:
for(int i=32;i--;)
{
int pixels = *(encoded++);
*(dest++)^=chunks32[pixels];
}
break;
}
}
}
//DSC::Debug::log("New encoded = %X", encoded);
return encoded;
}
int FrameDecoder::decode(int* buffer1, int* buffer2, char* frame_data)
{
int frame_header = *(frame_data++);
int dx=0, dy=0;
char* (*typed_decode_f)(char*, char*, int*) = typed_decode;
if((frame_header & 0x80)==0)
{
if(frame_header & 0b01100000)
{
dx = *(frame_data++);
dy = *(frame_data++);
if(dx>=128) dx=-256+dx;
if(dy>=128) dy=-256+dy;
}
typed_decode_f = typed_decode_xor;
}
//DSC::Debug::log("Frame data = %X", frame_data);
DSC::Debug::log("Diffing = %s", (frame_header & 0x80)==0 ? "YES" : "NO");
/*if((frame_header & 0x80)==0)
{
DSC::Debug::log("x,y = %i, %i", dx, dy);
}*/
void (*sh_nibbles)(int*, int, int, int*) = rsh_nibbles;
//dx=22;
if(dx<0)
{
sh_nibbles = lsh_nibbles;
dx=-dx;
}
if(dy>0)
{
for(int y=191;y>=0;y--)
{
if(y+dy<192)
{
sh_nibbles(buffer1+32*y, 32, dx, buffer1+32*(y+dy));
sh_nibbles(buffer2+32*y, 32, dx, buffer2+32*(y+dy));
}
else
{
for(int i=0;i<32;i++)
{
buffer1[32*y+i]=0;
buffer2[32*y+i]=0;
}
}
}
}
else
{
dy=-dy;
for(int y=0;y<192;y++)
{
if(y+dy<192)
{
sh_nibbles(buffer1+32*(y+dy), 32, dx, buffer1+32*y);
sh_nibbles(buffer2+32*(y+dy), 32, dx, buffer2+32*y);
}
else
{
for(int i=0;i<32;i++)
{
buffer1[32*y+i]=0;
buffer2[32*y+i]=0;
}
}
}
}
char* decode_src = typed_decode_f(frame_data, frame_data+96, buffer1);
typed_decode_f(frame_data+48, decode_src, buffer2);
return frame_header;
}