|
|
|
@ -320,8 +320,52 @@ struct Rom{ |
|
|
|
|
const float c3{PI/60.f}; |
|
|
|
|
Sprite&bitmap; |
|
|
|
|
std::unique_ptr<DistortionEffect>effect; |
|
|
|
|
float amplitude,frequency,compression,speed; |
|
|
|
|
Distorter(Sprite&bitmap) |
|
|
|
|
:bitmap(bitmap){} |
|
|
|
|
void setup(int ticks){ |
|
|
|
|
int t2{ticks*2}; |
|
|
|
|
amplitude=c1*(effect->amplitude()+effect->amplitudeAcceleration()*t2); |
|
|
|
|
frequency=c2*(effect->frequency()+(effect->frequencyAcceleration()*t2)); |
|
|
|
|
compression=1+(effect->compression()+(effect->compressionAcceleration()*t2))/256.f; |
|
|
|
|
speed=c3*speed*ticks; |
|
|
|
|
} |
|
|
|
|
float getAppliedOffset(int y){ |
|
|
|
|
float s=std::round(amplitude*sin(frequency*y+speed)); |
|
|
|
|
switch(effect->type()){ |
|
|
|
|
case DistortionEffect::HORIZONTAL:return s; |
|
|
|
|
case DistortionEffect::HORIZONTAL_INTERLACED:return y%2?s:-s; |
|
|
|
|
case DistortionEffect::VERTICAL:return fmod(floor(s+y*effect->compression()),256.f); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void computeFrame(PixelGameEngine*pge,int ticks,float alpha,bool erase){ |
|
|
|
|
setup(ticks); |
|
|
|
|
for(int y:std::views::iota(0,pge->ScreenHeight())){ |
|
|
|
|
float offset{getAppliedOffset(y)}; |
|
|
|
|
int L=effect->type()==DistortionEffect::VERTICAL?offset:y; |
|
|
|
|
for(int x:std::views::iota(0,pge->ScreenWidth())){ |
|
|
|
|
int dx=x; |
|
|
|
|
if(effect->type()==DistortionEffect::HORIZONTAL||effect->type()==DistortionEffect::HORIZONTAL_INTERLACED)dx=fmod(x+offset,pge->ScreenWidth()); |
|
|
|
|
if(erase){ |
|
|
|
|
Pixel newCol{bitmap.GetPixel(dx,L)}; |
|
|
|
|
newCol.r*=alpha; |
|
|
|
|
newCol.g*=alpha; |
|
|
|
|
newCol.b*=alpha; |
|
|
|
|
pge->Draw(dx,L,newCol); |
|
|
|
|
}else{ |
|
|
|
|
Pixel newCol{bitmap.GetPixel(dx,L)}; |
|
|
|
|
newCol.r*=alpha; |
|
|
|
|
newCol.g*=alpha; |
|
|
|
|
newCol.b*=alpha; |
|
|
|
|
Pixel mixedCol{pge->GetDrawTarget()->GetPixel(dx,L)}; |
|
|
|
|
mixedCol.r+=newCol.r; |
|
|
|
|
mixedCol.g+=newCol.g; |
|
|
|
|
mixedCol.b+=newCol.b; |
|
|
|
|
pge->Draw(dx,L,mixedCol); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct PaletteCycle{ |
|
|
|
@ -334,6 +378,51 @@ struct Rom{ |
|
|
|
|
originalCols.emplace_back(originalCols[i]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void cycle(){ |
|
|
|
|
if(speed==0)return; |
|
|
|
|
cycleCountdown=std::clamp(cycleCountdown-1,0,int(std::numeric_limits<byte>::max())); |
|
|
|
|
if(cycleCountdown<=0){ |
|
|
|
|
cycleColors(); |
|
|
|
|
cycleCount++; |
|
|
|
|
cycleCountdown=speed; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
void cycleColors(){ |
|
|
|
|
if(type==1||type==2){ |
|
|
|
|
int cycleLength{end1-start1+1}; |
|
|
|
|
int cycle1Position{cycleCount%cycleLength}; |
|
|
|
|
for(int i:std::views::iota(int(start1),end1+1)){ |
|
|
|
|
int newColor=i-cycle1Position; |
|
|
|
|
if(newColor<start1)newColor+=cycleLength; |
|
|
|
|
currentCols[i]=originalCols[newColor]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(type==2){ |
|
|
|
|
int cycleLength{end2-start2+1}; |
|
|
|
|
int cycle2Position{cycleCount%cycleLength}; |
|
|
|
|
for(int i:std::views::iota(int(start2),end2+1)){ |
|
|
|
|
int newColor=i-cycle2Position; |
|
|
|
|
if(newColor<start2)newColor+=cycleLength; |
|
|
|
|
currentCols[i]=originalCols[newColor]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if(type==3){ |
|
|
|
|
int cycleLength{end1-start1+1}; |
|
|
|
|
int cycle1Position{cycleCount%(cycleLength*2)}; |
|
|
|
|
for(int i:std::views::iota(int(start1),end1+1)){ |
|
|
|
|
int newColor=i+cycle1Position; |
|
|
|
|
if(newColor>end1){ |
|
|
|
|
int difference{newColor-end1-1}; |
|
|
|
|
newColor=end1-difference; |
|
|
|
|
if(newColor<start1){ |
|
|
|
|
difference=start1-newColor-1; |
|
|
|
|
newColor=start1+difference; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
currentCols[i]=originalCols[newColor]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
PixelGameEngine*pge; |
|
|
|
@ -343,6 +432,43 @@ struct Rom{ |
|
|
|
|
BackgroundGraphics&graphics; |
|
|
|
|
PaletteCycle cycle; |
|
|
|
|
uint_fast16_t backgroundInd; |
|
|
|
|
|
|
|
|
|
void drawTile(const int x,const int y,const int tile,const int subPalette,const bool verticalFlip,const bool horizontalFlip){ |
|
|
|
|
int px{},py{}; |
|
|
|
|
for(int i:std::views::iota(0,8)){ |
|
|
|
|
if(horizontalFlip)px=x+7-i; |
|
|
|
|
else px=x+i; |
|
|
|
|
for(int j:std::views::iota(0,8)){ |
|
|
|
|
if(verticalFlip)py=y+7-j; |
|
|
|
|
else py=y+j; |
|
|
|
|
spr->SetPixel(px,py,cycle.currentCols[graphics.tiles[tile][i][j]]); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void draw(){ |
|
|
|
|
int block{}; |
|
|
|
|
int tile{}; |
|
|
|
|
int subPalette{}; //Subpalette should always be zero....I don't understand?
|
|
|
|
|
int n{}; |
|
|
|
|
int b1{}; |
|
|
|
|
int b2{}; |
|
|
|
|
bool verticalFlip{false}; |
|
|
|
|
bool horizontalFlip{false}; |
|
|
|
|
for(int i:std::views::iota(0,32)){ |
|
|
|
|
for(int j:std::views::iota(0,32)){ |
|
|
|
|
n=j*32+i; |
|
|
|
|
b1=graphics.arrayGraphicsData[n*2]; |
|
|
|
|
b2=graphics.arrayGraphicsData[n*2+1]<<8; |
|
|
|
|
block=b1+b2; |
|
|
|
|
tile=block&0x3FF; |
|
|
|
|
verticalFlip=block&0x8000; |
|
|
|
|
horizontalFlip=block&0x4000; |
|
|
|
|
//subPalette=(block>>10)&7; //THIS SHOULD NOT BE NECESSARY!!!
|
|
|
|
|
drawTile(i*8,j*8,tile,0,verticalFlip,horizontalFlip); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
BackgroundLayer(PixelGameEngine*pge,uint_fast16_t backgroundInd,std::vector<BattleBackground>&backgrounds,std::vector<BackgroundPalette>&palettes,std::vector<BackgroundGraphics>&graphics,std::u8string_view data) |
|
|
|
|
:pge(pge),spr(new Sprite(256,256)),distorter(*spr),backgroundInd(backgroundInd),background(backgrounds[backgroundInd]),graphics(graphics[background.graphicsInd]),cycle(background,palettes[background.paletteInd]){ |
|
|
|
|
uint_fast32_t effectVal{((background.GetAnimation()>>16)&0xFF)}; |
|
|
|
@ -366,10 +492,20 @@ struct Rom{ |
|
|
|
|
backgroundInd=std::clamp(backgroundInd,0U,uint_fast16_t(backgrounds.size())); |
|
|
|
|
layer2=std::make_unique<BackgroundLayer>(nullptr,backgroundInd,backgrounds,palettes,graphics,data); |
|
|
|
|
} |
|
|
|
|
void AdvanceLayers(int tick,float alpha1,float alpha2){ |
|
|
|
|
layer1->cycle.cycle(); |
|
|
|
|
layer1->draw(); |
|
|
|
|
layer1->distorter.computeFrame(pge,tick,alpha1,true); |
|
|
|
|
layer2->cycle.cycle(); |
|
|
|
|
layer2->draw(); |
|
|
|
|
layer2->distorter.computeFrame(pge,tick,alpha2,false); |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
|
std::unique_ptr<BackgroundLayer>layer1,layer2; |
|
|
|
|
PixelGameEngine*pge; |
|
|
|
|
public: |
|
|
|
|
Rom(){ |
|
|
|
|
Rom(PixelGameEngine*pge) |
|
|
|
|
:pge(pge){ |
|
|
|
|
#pragma region Setup Reversed Bytes |
|
|
|
|
reversedBytes.resize(256); |
|
|
|
|
for(int i:std::views::iota(0U,reversedBytes.size())){ |
|
|
|
@ -398,8 +534,8 @@ public: |
|
|
|
|
graphics.emplace_back(data,i,graphicsBits[i]); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
layer1=std::make_unique<BackgroundLayer>(nullptr,0U,backgrounds,palettes,graphics,data); |
|
|
|
|
layer2=std::make_unique<BackgroundLayer>(nullptr,0U,backgrounds,palettes,graphics,data); |
|
|
|
|
layer1=std::make_unique<BackgroundLayer>(pge,0U,backgrounds,palettes,graphics,data); |
|
|
|
|
layer2=std::make_unique<BackgroundLayer>(pge,0U,backgrounds,palettes,graphics,data); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -413,11 +549,12 @@ public: |
|
|
|
|
sAppName = "Earthbound Battle Backgrounds"; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Rom rom; |
|
|
|
|
Rom*rom; |
|
|
|
|
|
|
|
|
|
public: |
|
|
|
|
bool OnUserCreate() override |
|
|
|
|
{ |
|
|
|
|
rom=new Rom(this); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -425,7 +562,7 @@ public: |
|
|
|
|
if(GetMouseWheel()<0)yOffset-=32; |
|
|
|
|
if(GetMouseWheel()>0)yOffset+=32; |
|
|
|
|
|
|
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundPalette&palette:rom.palettes){ |
|
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundPalette&palette:rom->palettes){ |
|
|
|
|
for(uint_fast8_t index=0;Pixel&col:palette.colors){ |
|
|
|
|
FillRectDecal(vf2d{index*8.f+8,row*8.f+yOffset},{8,8},col); |
|
|
|
|
index++; |
|
|
|
@ -444,17 +581,17 @@ public: |
|
|
|
|
|
|
|
|
|
DrawStringDecal({},std::format("Selected Palette: {}",selectedPalette)); |
|
|
|
|
|
|
|
|
|
if(GetKey(PGUP).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));; |
|
|
|
|
if(GetKey(PGUP).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(uint_fast8_t index=0;Pixel&col:palette.colors){ |
|
|
|
|
FillRectDecal(vf2d{index*8.f,8.f},{8,8},col); |
|
|
|
|
index++; |
|
|
|
|
} |
|
|
|
|
DrawRectDecal(vf2d{8.f,8.f},{8*16,8}); |
|
|
|
|
|
|
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundGraphics&graphics:rom.graphics){ |
|
|
|
|
for(uint_fast8_t row=0;Rom::BackgroundGraphics&graphics:rom->graphics){ |
|
|
|
|
for(uint_fast8_t col=0;Rom::Tile&tile:graphics.tiles){ |
|
|
|
|
for(int x{};x<tile.size();x++){ |
|
|
|
|
for(int y{};y<tile[x].size();y++){ |
|
|
|
@ -473,26 +610,51 @@ public: |
|
|
|
|
|
|
|
|
|
int yOffset{0}; |
|
|
|
|
float accumulatedTime{}; |
|
|
|
|
int tick{}; |
|
|
|
|
|
|
|
|
|
uint16_t selectedLayer1{}; |
|
|
|
|
uint16_t selectedLayer2{}; |
|
|
|
|
|
|
|
|
|
void runTick(){ |
|
|
|
|
float alpha1{1.f},alpha2{1.f}; |
|
|
|
|
if(rom.GetLayer1()->backgroundInd&&!rom.GetLayer2()->backgroundInd){ |
|
|
|
|
if(rom->GetLayer1()->backgroundInd&&!rom->GetLayer2()->backgroundInd){ |
|
|
|
|
alpha1=1.f; |
|
|
|
|
alpha2=0.f; |
|
|
|
|
} |
|
|
|
|
if(!rom.GetLayer1()->backgroundInd&&rom.GetLayer2()->backgroundInd){ |
|
|
|
|
if(!rom->GetLayer1()->backgroundInd&&rom->GetLayer2()->backgroundInd){ |
|
|
|
|
alpha1=0.f; |
|
|
|
|
alpha2=1.f; |
|
|
|
|
} |
|
|
|
|
rom->AdvanceLayers(tick,alpha1,alpha2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool OnUserUpdate(float fElapsedTime) override |
|
|
|
|
{ |
|
|
|
|
if(GetKey(RIGHT).bPressed){ |
|
|
|
|
selectedLayer1=std::clamp(selectedLayer1+1,0,int(rom->backgrounds.size())); |
|
|
|
|
rom->SetLayer1(selectedLayer1); |
|
|
|
|
} |
|
|
|
|
if(GetKey(LEFT).bPressed){ |
|
|
|
|
selectedLayer1=std::clamp(selectedLayer1-1,0,int(rom->backgrounds.size())); |
|
|
|
|
rom->SetLayer1(selectedLayer1); |
|
|
|
|
} |
|
|
|
|
if(GetKey(UP).bPressed){ |
|
|
|
|
selectedLayer2=std::clamp(selectedLayer2+1,0,int(rom->backgrounds.size())); |
|
|
|
|
rom->SetLayer2(selectedLayer2); |
|
|
|
|
} |
|
|
|
|
if(GetKey(DOWN).bPressed){ |
|
|
|
|
selectedLayer2=std::clamp(selectedLayer2-1,0,int(rom->backgrounds.size())); |
|
|
|
|
rom->SetLayer2(selectedLayer2); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
accumulatedTime+=fElapsedTime; |
|
|
|
|
while(accumulatedTime>=1/60.f){ |
|
|
|
|
runTick(); |
|
|
|
|
accumulatedTime-=1/60.f |
|
|
|
|
accumulatedTime-=1/60.f; |
|
|
|
|
tick++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
DrawStringDecal({},std::format("Layer 1: {} Layer 2: {}",selectedLayer1,selectedLayer2)); |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|