|
|
@ -8,10 +8,10 @@ |
|
|
|
using namespace olc; |
|
|
|
using namespace olc; |
|
|
|
|
|
|
|
|
|
|
|
struct Rom{ |
|
|
|
struct Rom{ |
|
|
|
const static uint16_t MIN_INDEX{}; |
|
|
|
const static uint_fast16_t MIN_INDEX{}; |
|
|
|
const static uint16_t MAX_INDEX{326U}; |
|
|
|
const static uint_fast16_t MAX_INDEX{326U}; |
|
|
|
std::array<uint32_t,114>paletteBits; |
|
|
|
std::array<uint_fast32_t,114>paletteBits; |
|
|
|
std::array<uint32_t,103>graphicsBits; |
|
|
|
std::array<uint_fast32_t,103>graphicsBits; |
|
|
|
enum Command{ |
|
|
|
enum Command{ |
|
|
|
UNCOMPRESSED_BLOCK, |
|
|
|
UNCOMPRESSED_BLOCK, |
|
|
|
RUN_LENGTH_ENCODED_BYTE, |
|
|
|
RUN_LENGTH_ENCODED_BYTE, |
|
|
@ -23,8 +23,8 @@ struct Rom{ |
|
|
|
UNKNOWN_2, |
|
|
|
UNKNOWN_2, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static uint32_t snesToHex(uint32_t addr,bool header=true){ |
|
|
|
static uint_fast32_t snesToHex(uint_fast32_t addr,bool header=true){ |
|
|
|
uint32_t newAddr{addr}; |
|
|
|
uint_fast32_t newAddr{addr}; |
|
|
|
if(newAddr>=0x400000&&newAddr<0x600000);//NO-OP
|
|
|
|
if(newAddr>=0x400000&&newAddr<0x600000);//NO-OP
|
|
|
|
else if(newAddr>=0xC00000&&newAddr<0x1000000)newAddr-=0xC00000; |
|
|
|
else if(newAddr>=0xC00000&&newAddr<0x1000000)newAddr-=0xC00000; |
|
|
|
else throw std::out_of_range{std::format("SNES address out of range: {}",newAddr)}; |
|
|
|
else throw std::out_of_range{std::format("SNES address out of range: {}",newAddr)}; |
|
|
@ -32,8 +32,8 @@ struct Rom{ |
|
|
|
if(header)newAddr+=0x200; |
|
|
|
if(header)newAddr+=0x200; |
|
|
|
return newAddr-0xA0200; |
|
|
|
return newAddr-0xA0200; |
|
|
|
} |
|
|
|
} |
|
|
|
static uint32_t hexToSnes(uint32_t addr,bool header=true){ |
|
|
|
static uint_fast32_t hexToSnes(uint_fast32_t addr,bool header=true){ |
|
|
|
uint32_t newAddr{addr}; |
|
|
|
uint_fast32_t newAddr{addr}; |
|
|
|
if(header)newAddr-=0x200; |
|
|
|
if(header)newAddr-=0x200; |
|
|
|
if(newAddr>=0&&newAddr<0x400000)return newAddr+0xC00000; |
|
|
|
if(newAddr>=0&&newAddr<0x400000)return newAddr+0xC00000; |
|
|
|
else if(newAddr>=0x400000&&newAddr<0x600000)return newAddr; |
|
|
|
else if(newAddr>=0x400000&&newAddr<0x600000)return newAddr; |
|
|
@ -41,22 +41,22 @@ struct Rom{ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct DataBlock{ |
|
|
|
struct DataBlock{ |
|
|
|
uint32_t addr,ptr; |
|
|
|
uint_fast32_t addr,ptr; |
|
|
|
std::u8string_view data; |
|
|
|
std::u8string_view data; |
|
|
|
DataBlock(std::u8string_view data,uint32_t loc) |
|
|
|
DataBlock(std::u8string_view data,uint_fast32_t loc) |
|
|
|
:data(data){ |
|
|
|
:data(data){ |
|
|
|
addr=ptr=loc; |
|
|
|
addr=ptr=loc; |
|
|
|
} |
|
|
|
} |
|
|
|
uint8_t readInt8(){ |
|
|
|
uint_fast8_t readInt8(){ |
|
|
|
return data[ptr++]; |
|
|
|
return data[ptr++]; |
|
|
|
} |
|
|
|
} |
|
|
|
uint16_t readShort(){ |
|
|
|
uint_fast16_t readShort(){ |
|
|
|
return readInt8()|(readInt8()<<8); |
|
|
|
return readInt8()|(readInt8()<<8); |
|
|
|
} |
|
|
|
} |
|
|
|
uint32_t readInt32(){ |
|
|
|
uint_fast32_t readInt32(){ |
|
|
|
return readInt8()|(readInt8()<<8)|(readInt8()<<16)|(readInt8()<<24); |
|
|
|
return readInt8()|(readInt8()<<8)|(readInt8()<<16)|(readInt8()<<24); |
|
|
|
} |
|
|
|
} |
|
|
|
uint32_t getCompressedSize(uint32_t pointer){ |
|
|
|
uint_fast32_t getCompressedSize(uint_fast32_t pointer){ |
|
|
|
int32_t bpos{}; |
|
|
|
int32_t bpos{}; |
|
|
|
int32_t pos{int32_t(pointer)}; |
|
|
|
int32_t pos{int32_t(pointer)}; |
|
|
|
int32_t bpos2{}; |
|
|
|
int32_t bpos2{}; |
|
|
@ -111,16 +111,16 @@ struct Rom{ |
|
|
|
} |
|
|
|
} |
|
|
|
return bpos; |
|
|
|
return bpos; |
|
|
|
} |
|
|
|
} |
|
|
|
std::vector<uint16_t>decompress(){ |
|
|
|
std::vector<uint_fast16_t>decompress(){ |
|
|
|
uint32_t size{getCompressedSize(ptr)}; |
|
|
|
uint_fast32_t size{getCompressedSize(ptr)}; |
|
|
|
if(size<1)throw std::runtime_error(std::format("Got an invalid data size of {}",size)); |
|
|
|
if(size<1)throw std::runtime_error(std::format("Got an invalid data size of {}",size)); |
|
|
|
std::vector<uint16_t>blockOutput; |
|
|
|
std::vector<uint_fast16_t>blockOutput; |
|
|
|
blockOutput.resize(size); |
|
|
|
blockOutput.resize(size); |
|
|
|
decompressBlock(ptr,blockOutput); |
|
|
|
decompressBlock(ptr,blockOutput); |
|
|
|
return blockOutput; |
|
|
|
return blockOutput; |
|
|
|
} |
|
|
|
} |
|
|
|
private: |
|
|
|
private: |
|
|
|
void decompressBlock(uint32_t ptrStart,std::vector<uint16_t>&block){ |
|
|
|
void decompressBlock(uint_fast32_t ptrStart,std::vector<uint_fast16_t>&block){ |
|
|
|
size_t maxLength{block.size()}; |
|
|
|
size_t maxLength{block.size()}; |
|
|
|
int32_t pos{int32_t(ptrStart)}; |
|
|
|
int32_t pos{int32_t(ptrStart)}; |
|
|
|
int32_t bpos{}; |
|
|
|
int32_t bpos{}; |
|
|
@ -184,8 +184,8 @@ struct Rom{ |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct BattleBackground{ |
|
|
|
struct BattleBackground{ |
|
|
|
BattleBackground(std::u8string_view data,uint32_t index){ |
|
|
|
BattleBackground(std::u8string_view data,uint_fast32_t index){ |
|
|
|
DataBlock readData{data,0xDCA1+index*uint32_t(this->data.size())}; |
|
|
|
DataBlock readData{data,0xDCA1+index*uint_fast32_t(this->data.size())}; |
|
|
|
for(int i=0;i<this->data.size();i++){ |
|
|
|
for(int i=0;i<this->data.size();i++){ |
|
|
|
this->data[i]=readData.readInt8(); |
|
|
|
this->data[i]=readData.readInt8(); |
|
|
|
} |
|
|
|
} |
|
|
@ -206,37 +206,37 @@ struct Rom{ |
|
|
|
byte verticalMovement; |
|
|
|
byte verticalMovement; |
|
|
|
byte horizontalAcceleration; |
|
|
|
byte horizontalAcceleration; |
|
|
|
byte verticalAcceleration; |
|
|
|
byte verticalAcceleration; |
|
|
|
uint32_t animationEffectsData; |
|
|
|
uint_fast32_t animationEffectsData; |
|
|
|
}; |
|
|
|
}; |
|
|
|
}; |
|
|
|
}; |
|
|
|
uint32_t GetAnimation(){ |
|
|
|
uint_fast32_t GetAnimation(){ |
|
|
|
return (data[13]<<24)+(data[14]<<16)+(data[15]<<8)+data[16]; |
|
|
|
return (data[13]<<24)+(data[14]<<16)+(data[15]<<8)+data[16]; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
struct BackgroundPalette{ |
|
|
|
struct BackgroundPalette{ |
|
|
|
std::vector<Pixel>colors; |
|
|
|
std::vector<Pixel>colors; |
|
|
|
byte bpp; |
|
|
|
byte bpp; |
|
|
|
uint32_t addr; |
|
|
|
uint_fast32_t addr; |
|
|
|
BackgroundPalette(std::u8string_view data,uint16_t index,byte bpp) |
|
|
|
BackgroundPalette(std::u8string_view data,uint_fast16_t index,byte bpp) |
|
|
|
:bpp(bpp){ |
|
|
|
:bpp(bpp){ |
|
|
|
DataBlock pointer{data,0xDAD9U+index*4U}; |
|
|
|
DataBlock pointer{data,0xDAD9U+index*4U}; |
|
|
|
uint32_t addr=snesToHex(pointer.readInt32()); |
|
|
|
uint_fast32_t addr=snesToHex(pointer.readInt32()); |
|
|
|
DataBlock dataBlock{data,addr}; |
|
|
|
DataBlock dataBlock{data,addr}; |
|
|
|
this->addr=addr; |
|
|
|
this->addr=addr; |
|
|
|
if(bpp!=2&&bpp!=4)throw std::invalid_argument{std::format("Palette Error: Incorrect color depth specified. Must be 2 or 4, provided {}",bpp)}; |
|
|
|
if(bpp!=2&&bpp!=4)throw std::invalid_argument{std::format("Palette Error: Incorrect color depth specified. Must be 2 or 4, provided {}",bpp)}; |
|
|
|
for(uint8_t i:std::views::iota(0,pow(2,bpp))){ |
|
|
|
for(uint_fast8_t i:std::views::iota(0,pow(2,bpp))){ |
|
|
|
uint16_t clr16{dataBlock.readShort()}; |
|
|
|
uint_fast16_t clr16{dataBlock.readShort()}; |
|
|
|
uint8_t b{((clr16>>10)&31)*8U}; |
|
|
|
uint_fast8_t b{((clr16>>10)&31)*8U}; |
|
|
|
uint8_t g{((clr16>>5)&31)*8U}; |
|
|
|
uint_fast8_t g{((clr16>>5)&31)*8U}; |
|
|
|
uint8_t r{(clr16&31)*8U}; |
|
|
|
uint_fast8_t r{(clr16&31)*8U}; |
|
|
|
colors.emplace_back(r,g,b); |
|
|
|
colors.emplace_back(r,g,b); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
using Tile=std::array<std::array<int,8>,8>; |
|
|
|
using Tile=std::array<std::array<int,8>,8>; |
|
|
|
struct BackgroundGraphics{ |
|
|
|
struct BackgroundGraphics{ |
|
|
|
std::vector<uint16_t>graphicsData; |
|
|
|
std::vector<uint_fast16_t>graphicsData; |
|
|
|
std::vector<uint16_t>arrayGraphicsData; |
|
|
|
std::vector<uint_fast16_t>arrayGraphicsData; |
|
|
|
std::vector<Tile>tiles; |
|
|
|
std::vector<Tile>tiles; |
|
|
|
byte bpp; |
|
|
|
byte bpp; |
|
|
|
private: |
|
|
|
private: |
|
|
@ -259,14 +259,14 @@ struct Rom{ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
public: |
|
|
|
public: |
|
|
|
BackgroundGraphics(std::u8string_view data,uint16_t index,byte bpp) |
|
|
|
BackgroundGraphics(std::u8string_view data,uint_fast16_t index,byte bpp) |
|
|
|
:bpp(bpp){ |
|
|
|
:bpp(bpp){ |
|
|
|
DataBlock graphicsPtr{data,0xD7A1U+index*4U}; |
|
|
|
DataBlock graphicsPtr{data,0xD7A1U+index*4U}; |
|
|
|
DataBlock loadGraphicsPtr{data,snesToHex(graphicsPtr.readInt32())}; |
|
|
|
DataBlock loadGraphicsPtr{data,snesToHex(graphicsPtr.readInt32())}; |
|
|
|
graphicsData=loadGraphicsPtr.decompress(); |
|
|
|
graphicsData=loadGraphicsPtr.decompress(); |
|
|
|
buildTiles(); |
|
|
|
buildTiles(); |
|
|
|
DataBlock arrayPtrBlock{data,0xD93DU+index*4}; |
|
|
|
DataBlock arrayPtrBlock{data,0xD93DU+index*4}; |
|
|
|
uint32_t arrayPtr{snesToHex(arrayPtrBlock.readInt32())}; |
|
|
|
uint_fast32_t arrayPtr{snesToHex(arrayPtrBlock.readInt32())}; |
|
|
|
DataBlock arrayBlock{data,arrayPtr}; |
|
|
|
DataBlock arrayBlock{data,arrayPtr}; |
|
|
|
arrayGraphicsData=arrayBlock.decompress(); |
|
|
|
arrayGraphicsData=arrayBlock.decompress(); |
|
|
|
} |
|
|
|
} |
|
|
@ -283,6 +283,19 @@ struct Rom{ |
|
|
|
:bitmap(bitmap){} |
|
|
|
:bitmap(bitmap){} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct DistortionEffect{ |
|
|
|
|
|
|
|
enum{ |
|
|
|
|
|
|
|
HORIZONTAL=1, |
|
|
|
|
|
|
|
HORIZONTAL_INTERLACED=2, |
|
|
|
|
|
|
|
VERTICAL=3 |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
uint_fast16_t type(){ |
|
|
|
|
|
|
|
return std::clamp(data[2],uint_fast8_t(1),uint_fast8_t(3U)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
|
std::array<uint_fast8_t,17>data; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct PaletteCycle{ |
|
|
|
struct PaletteCycle{ |
|
|
|
std::vector<Pixel>originalCols; |
|
|
|
std::vector<Pixel>originalCols; |
|
|
|
std::vector<Pixel>currentCols; |
|
|
|
std::vector<Pixel>currentCols; |
|
|
@ -301,7 +314,7 @@ struct Rom{ |
|
|
|
PaletteCycle cycle; |
|
|
|
PaletteCycle cycle; |
|
|
|
BattleBackground&background; |
|
|
|
BattleBackground&background; |
|
|
|
BackgroundGraphics&graphics; |
|
|
|
BackgroundGraphics&graphics; |
|
|
|
BackgroundLayer(PixelGameEngine*pge,uint8_t pgeLayer,uint16_t backgroundInd,std::vector<BattleBackground>&backgrounds,std::vector<BackgroundPalette>&palettes,std::vector<BackgroundGraphics>&graphics) |
|
|
|
BackgroundLayer(PixelGameEngine*pge,uint_fast16_t backgroundInd,std::vector<BattleBackground>&backgrounds,std::vector<BackgroundPalette>&palettes,std::vector<BackgroundGraphics>&graphics) |
|
|
|
:pge(pge),spr(new Sprite(256,256)),distorter(*spr),background(backgrounds[backgroundInd]),graphics(graphics[background.graphicsInd]),cycle(background,palettes[background.paletteInd]){} |
|
|
|
:pge(pge),spr(new Sprite(256,256)),distorter(*spr),background(backgrounds[backgroundInd]),graphics(graphics[background.graphicsInd]),cycle(background,palettes[background.paletteInd]){} |
|
|
|
}; |
|
|
|
}; |
|
|
|
std::u8string data; |
|
|
|
std::u8string data; |
|
|
@ -309,14 +322,14 @@ struct Rom{ |
|
|
|
std::vector<BattleBackground>backgrounds; |
|
|
|
std::vector<BattleBackground>backgrounds; |
|
|
|
std::vector<BackgroundPalette>palettes; |
|
|
|
std::vector<BackgroundPalette>palettes; |
|
|
|
std::vector<BackgroundGraphics>graphics; |
|
|
|
std::vector<BackgroundGraphics>graphics; |
|
|
|
BackgroundLayer layer1{nullptr,0U,0U,backgrounds},layer2{nullptr,1U,0U,backgrounds}; |
|
|
|
BackgroundLayer layer1{nullptr,0U,backgrounds,palettes,graphics},layer2{nullptr,0U,backgrounds,palettes,graphics}; |
|
|
|
Rom(){ |
|
|
|
Rom(){ |
|
|
|
#pragma region Setup Reversed Bytes |
|
|
|
#pragma region Setup Reversed Bytes |
|
|
|
reversedBytes.resize(256); |
|
|
|
reversedBytes.resize(256); |
|
|
|
for(int i:std::views::iota(0U,reversedBytes.size())){ |
|
|
|
for(int i:std::views::iota(0U,reversedBytes.size())){ |
|
|
|
uint8_t newNumb{}; |
|
|
|
uint_fast8_t newNumb{}; |
|
|
|
for(int digit=0;digit<8;digit++){ |
|
|
|
for(int digit=0;digit<8;digit++){ |
|
|
|
uint8_t digitVal{1U<<digit}; |
|
|
|
uint_fast8_t digitVal{1U<<digit}; |
|
|
|
if(i&digitVal)newNumb|=1<<(7-digit); |
|
|
|
if(i&digitVal)newNumb|=1<<(7-digit); |
|
|
|
} |
|
|
|
} |
|
|
|
reversedBytes[i]=newNumb; |
|
|
|
reversedBytes[i]=newNumb; |
|
|
@ -327,15 +340,15 @@ struct Rom{ |
|
|
|
std::ifstream dataStream{"truncated_backgrounds.dat",std::ios_base::binary}; |
|
|
|
std::ifstream dataStream{"truncated_backgrounds.dat",std::ios_base::binary}; |
|
|
|
while(dataStream.good())data+=dataStream.get(); |
|
|
|
while(dataStream.good())data+=dataStream.get(); |
|
|
|
|
|
|
|
|
|
|
|
for(uint16_t i:std::views::iota(0U,MAX_INDEX+1U)){ |
|
|
|
for(uint_fast16_t i:std::views::iota(0U,MAX_INDEX+1U)){ |
|
|
|
backgrounds.emplace_back(data,i); |
|
|
|
backgrounds.emplace_back(data,i); |
|
|
|
paletteBits[backgrounds.back().paletteInd]=backgrounds.back().bbp; |
|
|
|
paletteBits[backgrounds.back().paletteInd]=backgrounds.back().bbp; |
|
|
|
graphicsBits[backgrounds.back().graphicsInd]=backgrounds.back().bbp; |
|
|
|
graphicsBits[backgrounds.back().graphicsInd]=backgrounds.back().bbp; |
|
|
|
} |
|
|
|
} |
|
|
|
for(uint16_t i:std::views::iota(0U,paletteBits.size())){ |
|
|
|
for(uint_fast16_t i:std::views::iota(0U,paletteBits.size())){ |
|
|
|
palettes.emplace_back(data,i,paletteBits[i]); |
|
|
|
palettes.emplace_back(data,i,paletteBits[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
for(uint16_t i:std::views::iota(0U,graphicsBits.size())){ |
|
|
|
for(uint_fast16_t i:std::views::iota(0U,graphicsBits.size())){ |
|
|
|
graphics.emplace_back(data,i,graphicsBits[i]); |
|
|
|
graphics.emplace_back(data,i,graphicsBits[i]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -363,8 +376,8 @@ public: |
|
|
|
if(GetMouseWheel()<0)yOffset-=32; |
|
|
|
if(GetMouseWheel()<0)yOffset-=32; |
|
|
|
if(GetMouseWheel()>0)yOffset+=32; |
|
|
|
if(GetMouseWheel()>0)yOffset+=32; |
|
|
|
|
|
|
|
|
|
|
|
for(uint8_t row=0;Rom::BackgroundPalette&palette:rom.palettes){ |
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundPalette&palette:rom.palettes){ |
|
|
|
for(uint8_t index=0;Pixel&col:palette.colors){ |
|
|
|
for(uint_fast8_t index=0;Pixel&col:palette.colors){ |
|
|
|
FillRectDecal(vf2d{index*8.f+8,row*8.f+yOffset},{8,8},col); |
|
|
|
FillRectDecal(vf2d{index*8.f+8,row*8.f+yOffset},{8,8},col); |
|
|
|
index++; |
|
|
|
index++; |
|
|
|
} |
|
|
|
} |
|
|
@ -372,7 +385,7 @@ public: |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
uint8_t selectedPalette{}; |
|
|
|
uint_fast8_t selectedPalette{}; |
|
|
|
|
|
|
|
|
|
|
|
void GraphicsDisplayTest(){ |
|
|
|
void GraphicsDisplayTest(){ |
|
|
|
if(GetMouseWheel()<0)yOffset-=32; |
|
|
|
if(GetMouseWheel()<0)yOffset-=32; |
|
|
@ -386,14 +399,14 @@ public: |
|
|
|
if(GetKey(PGDN).bPressed)selectedPalette=std::clamp(int(selectedPalette)+1,0,int(rom.palettes.size()-1));; |
|
|
|
if(GetKey(PGDN).bPressed)selectedPalette=std::clamp(int(selectedPalette)+1,0,int(rom.palettes.size()-1));; |
|
|
|
|
|
|
|
|
|
|
|
Rom::BackgroundPalette&palette{rom.palettes[selectedPalette]}; |
|
|
|
Rom::BackgroundPalette&palette{rom.palettes[selectedPalette]}; |
|
|
|
for(uint8_t index=0;Pixel&col:palette.colors){ |
|
|
|
for(uint_fast8_t index=0;Pixel&col:palette.colors){ |
|
|
|
FillRectDecal(vf2d{index*8.f,8.f},{8,8},col); |
|
|
|
FillRectDecal(vf2d{index*8.f,8.f},{8,8},col); |
|
|
|
index++; |
|
|
|
index++; |
|
|
|
} |
|
|
|
} |
|
|
|
DrawRectDecal(vf2d{8.f,8.f},{8*16,8}); |
|
|
|
DrawRectDecal(vf2d{8.f,8.f},{8*16,8}); |
|
|
|
|
|
|
|
|
|
|
|
for(uint8_t row=0;Rom::BackgroundGraphics&graphics:rom.graphics){ |
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundGraphics&graphics:rom.graphics){ |
|
|
|
for(uint8_t col=0;Rom::Tile&tile:graphics.tiles){ |
|
|
|
for(uint_fast8_t col=0;Rom::Tile&tile:graphics.tiles){ |
|
|
|
for(int x{};x<tile.size();x++){ |
|
|
|
for(int x{};x<tile.size();x++){ |
|
|
|
for(int y{};y<tile[x].size();y++){ |
|
|
|
for(int y{};y<tile[x].size();y++){ |
|
|
|
int paletteInd{tile[x][y]}; |
|
|
|
int paletteInd{tile[x][y]}; |
|
|
|