diff --git a/EarthboundBattleBackgrounds/EarthboundBattleBackgrounds/main.cpp b/EarthboundBattleBackgrounds/EarthboundBattleBackgrounds/main.cpp index f30431d..a544376 100644 --- a/EarthboundBattleBackgrounds/EarthboundBattleBackgrounds/main.cpp +++ b/EarthboundBattleBackgrounds/EarthboundBattleBackgrounds/main.cpp @@ -320,8 +320,52 @@ struct Rom{ const float c3{PI/60.f}; Sprite&bitmap; std::unique_ptreffect; + 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::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(newColorend1){ + int difference{newColor-end1-1}; + newColor=end1-difference; + if(newColorSetPixel(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&backgrounds,std::vector&palettes,std::vector&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(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_ptrlayer1,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(nullptr,0U,backgrounds,palettes,graphics,data); - layer2=std::make_unique(nullptr,0U,backgrounds,palettes,graphics,data); + layer1=std::make_unique(pge,0U,backgrounds,palettes,graphics,data); + layer2=std::make_unique(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{};xbackgroundInd&&!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; } }; diff --git a/EarthboundBattleBackgrounds/x64/Debug/EarthboundBattleBackgrounds.exe b/EarthboundBattleBackgrounds/x64/Debug/EarthboundBattleBackgrounds.exe index 9bde18b..02459be 100644 Binary files a/EarthboundBattleBackgrounds/x64/Debug/EarthboundBattleBackgrounds.exe and b/EarthboundBattleBackgrounds/x64/Debug/EarthboundBattleBackgrounds.exe differ