diff --git a/src/Checkpoint.cpp b/src/Checkpoint.cpp index c87110c..d3b0b4b 100644 --- a/src/Checkpoint.cpp +++ b/src/Checkpoint.cpp @@ -72,9 +72,12 @@ void Checkpoint::DrawCheckpoints(TransformedView&tv){ const Animate2D::Frame&frame{checkpoint.animation.GetFrame(checkpoint.internal_animState)}; if(checkpoint.animation.GetState(checkpoint.internal_animState)!=AnimationState::DEFAULT){ HamsterGame::Game().SetDecalMode(DecalMode::ADDITIVE); + HamsterGame::Game().SetZ(0.007f); tv.DrawPartialRotatedDecal(checkpoint.pos,frame.GetSourceImage()->Decal(),0.f,frame.GetSourceRect().size/2,frame.GetSourceRect().pos,frame.GetSourceRect().size,{1.1f,1.1f}); + HamsterGame::Game().SetZ(0.009f); HamsterGame::Game().SetDecalMode(DecalMode::NORMAL); } + HamsterGame::Game().SetZ(0.009f); tv.DrawPartialRotatedDecal(checkpoint.pos,frame.GetSourceImage()->Decal(),0.f,frame.GetSourceRect().size/2,frame.GetSourceRect().pos,frame.GetSourceRect().size); geom2d::lineplayerToCheckpointLine{geom2d::line(Hamster::GetPlayer().GetPos(),checkpoint.pos)}; diff --git a/src/FloatingText.cpp b/src/FloatingText.cpp index 8ca06d9..9871921 100644 --- a/src/FloatingText.cpp +++ b/src/FloatingText.cpp @@ -72,13 +72,14 @@ void FloatingText::Draw(TransformedView&tv){ const vf2d strSize{HamsterGame::Game().GetTextSize(text)}; uint8_t alpha{uint8_t(util::lerp(0U,255U,lifetime/4.f))}; - + + HamsterGame::Game().SetZ(0.014f); for(int y:std::ranges::iota_view(-1,2)){ for(int x:std::ranges::iota_view(-1,2)){ tv.DrawRotatedStringDecal(pos+vi2d{x,y},text,0.f,strSize/2,{0,0,0,alpha},scale); } } - HamsterGame::Game().SetZ(0.01f); + HamsterGame::Game().SetZ(0.015f); tv.DrawRotatedStringDecal(pos,text,0.f,strSize/2,{currentCol.r,currentCol.g,currentCol.b,uint8_t(currentCol.a*(alpha/255.f))},scale); HamsterGame::Game().SetZ(0.f); } diff --git a/src/Hamster.cpp b/src/Hamster.cpp index b059ddc..68cb14c 100644 --- a/src/Hamster.cpp +++ b/src/Hamster.cpp @@ -67,10 +67,18 @@ void Hamster::UpdateHamsters(const float fElapsedTime){ h.HandleCollision(); switch(h.state){ case NORMAL:{ - if(h.bumpTimer<=0.f&&!h.CollectedAllCheckpoints()){ + if(h.CanMove()){ if(h.IsPlayerControlled){ h.HandlePlayerControls(); }else{ + if(!h.hamsterJet.has_value()){ + h.ObtainPowerup(Powerup::JET); + Powerup tempJetPowerup{{},Powerup::JET}; + tempJetPowerup.OnPowerupObtain(h); + h.SetState(FLYING); + h.lastSafeLocation.reset(); + h.hamsterJet.emplace(h); + } //TODO: NPC controls. } } @@ -181,17 +189,17 @@ void Hamster::DrawHamsters(TransformedView&tv){ yHopAmt=-abs(sin(geom2d::pi*(animCycle/0.35f)))*12.f; } if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); - HamsterGame::Game().SetZ(h.z); + HamsterGame::Game().SetZ(h.z+0.02f); tv.DrawRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},HamsterGame::GetGFX("shadow.png").Decal(),0.f,HamsterGame::GetGFX("shadow.png").Sprite()->Size()/2); - HamsterGame::Game().SetZ(h.z+0.005f); + HamsterGame::Game().SetZ(h.z+0.025f); tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY+yHopAmt},img.GetSourceImage()->Decal(),0.f,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale*vf2d{facingXScale,1.f},PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); - HamsterGame::Game().SetZ(h.z); + HamsterGame::Game().SetZ(0.f); }else{ if(h.hamsterJet.has_value())h.hamsterJet.value().Draw(); - HamsterGame::Game().SetZ(h.z); + HamsterGame::Game().SetZ(h.z+0.02f); if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelBottomImg.GetSourceImage()->Decal(),h.rot,wheelBottomImg.GetSourceRect().size/2,wheelBottomImg.GetSourceRect().pos,wheelBottomImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},img.GetSourceImage()->Decal(),h.rot,img.GetSourceRect().size/2,img.GetSourceRect().pos,img.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,WHITE,h.imgScale)); - HamsterGame::Game().SetZ(h.z+0.01f); + HamsterGame::Game().SetZ(h.z+0.025f); if(h.HasPowerup(Powerup::WHEEL))tv.DrawPartialRotatedDecal(h.pos+vf2d{0.f,h.drawingOffsetY},wheelTopImg.GetSourceImage()->Decal(),h.rot,wheelTopImg.GetSourceRect().size/2,wheelTopImg.GetSourceRect().pos,wheelTopImg.GetSourceRect().size,vf2d{1.f,1.f}*h.imgScale,PixelLerp(h.shrinkEffectColor,{255,255,255,192},h.imgScale)); HamsterGame::Game().SetZ(0.f); } @@ -363,7 +371,7 @@ const float Hamster::GetRadius()const{ } const Terrain::TerrainType Hamster::GetTerrainStandingOn()const{ - if(state==FLYING)return Terrain::ROCK; + if(FlyingInTheAir())return Terrain::ROCK; return HamsterGame::Game().GetTerrainTypeAtPos(GetPos()); } @@ -381,7 +389,7 @@ const float Hamster::GetTimeToMaxSpeed()const{ else if(!HasPowerup(Powerup::SWAMP)&&GetTerrainStandingOn()==Terrain::SWAMP)finalTimeToMaxSpd*=1.25; if(hamsterJet.has_value()){ if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalTimeToMaxSpd*=2.f; - else if(state==FLYING)finalTimeToMaxSpd*=3.f; + else if(FlyingInTheAir())finalTimeToMaxSpd*=3.f; } return finalTimeToMaxSpd; } @@ -417,7 +425,7 @@ const float Hamster::GetMaxSpeed()const{ if(HasPowerup(Powerup::WHEEL))finalMaxSpd*=1.5f; if(hamsterJet.has_value()){ if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalMaxSpd*=1.5f; - else if(state==FLYING)finalMaxSpd*=8.f; + else if(FlyingInTheAir())finalMaxSpd*=8.f; } return finalMaxSpd; } @@ -427,7 +435,7 @@ const float Hamster::GetFriction()const{ else if(!HasPowerup(Powerup::SWAMP)&&GetTerrainStandingOn()==Terrain::SWAMP)finalFriction*=0.6f; if(hamsterJet.has_value()){ if(hamsterJet.value().GetState()==HamsterJet::LANDING)finalFriction*=1.5f; - else if(state==FLYING)finalFriction*=8.f; + else if(FlyingInTheAir())finalFriction*=8.f; } return finalFriction; } @@ -588,4 +596,11 @@ const Hamster::HamsterState&Hamster::GetState()const{ const bool Hamster::BurnedOrDrowned()const{ return GetState()==WAIT; +} +const bool Hamster::CanMove()const{ + return bumpTimer<=0.f&&!CollectedAllCheckpoints(); +} + +const bool Hamster::FlyingInTheAir()const{ + return GetState()==FLYING&&hamsterJet.value().GetZ()>0.5f&&GetZ()>0.5f; } \ No newline at end of file diff --git a/src/Hamster.h b/src/Hamster.h index 9a07ad3..569c1f0 100644 --- a/src/Hamster.h +++ b/src/Hamster.h @@ -162,4 +162,6 @@ public: static const std::vector&GetHamsters(); const HamsterState&GetState()const; const bool BurnedOrDrowned()const; + const bool CanMove()const; + const bool FlyingInTheAir()const; }; \ No newline at end of file diff --git a/src/HamsterGame.cpp b/src/HamsterGame.cpp index 5bc5163..8ca2814 100644 --- a/src/HamsterGame.cpp +++ b/src/HamsterGame.cpp @@ -32,7 +32,7 @@ bool HamsterGame::OnUserCreate(){ renderer.SetProjection(90.0f, (float)SCREEN_FRAME.size.x/(float)SCREEN_FRAME.size.y, 0.1f, 1000.0f, 0, SCREEN_FRAME.pos.y, 512, SCREEN_FRAME.size.y); std::vectorradarCircle; - for(int i=360;i>=0;i-=4){ + for(int i=360;i>=0;i-=20){ float angle=util::degToRad(float(i))-geom2d::pi/2; if(i==360){radarCircle.push_back(vf2d{cos(angle),sin(angle)}*43+vf2d{43,44});} radarCircle.push_back(vf2d{cos(angle),sin(angle)}*43+vf2d{43,44}); @@ -184,11 +184,12 @@ void HamsterGame::UpdateGame(const float fElapsedTime){ } void HamsterGame::DrawGame(){ - SetZ(-0.001f); + SetZ(-0.01f); tv.DrawPartialDecal({-3200,-3200},currentMap.value().GetData().GetMapData().MapSize*16+vf2d{6400,6400},animatedWaterTile.Decal(),{0,0},currentMap.value().GetData().GetMapData().MapSize*16+vf2d{6400,6400}); - SetZ(0.f); + SetZ(-0.0005f); DrawLevelTiles(); Checkpoint::DrawCheckpoints(tv); + SetZ(0.01f); Powerup::DrawPowerups(tv); Hamster::DrawHamsters(tv); SetZ(3.f); @@ -322,11 +323,9 @@ bool HamsterGame::OnUserUpdate(float fElapsedTime){ } const Renderable&HamsterGame::GetGFX(const std::string&img){ - if(!GFX.count(img))throw std::runtime_error{std::format("Image {} does not exist!",img)}; return GFX[img]; } const Animate2D::Animation&HamsterGame::GetAnimations(const std::string&img){ - if(!ANIMATIONS.count(img))throw std::runtime_error{std::format("Animations for {} does not exist!",img)}; return ANIMATIONS[img]; } @@ -433,25 +432,38 @@ void HamsterGame::Apply3DTransform(std::vector&decals){ renderer.SetTransform(matWorld); + float zIncrementer{0.f}; + for(DecalInstance&decal:oldDecals){ SetDecalMode(decal.mode); - if(decal.transform==GFX3DTransform::NO_TRANSFORM)foregroundDecals.emplace_back(decal); + if(decal.transform==GFX3DTransform::NO_TRANSFORM){ + foregroundDecals.emplace_back(decal); + } else if(decal.points==3){ GFX3D::triangle tri{{{decal.pos[0].x,decal.pos[0].y,decal.z[0],1.f},{decal.pos[1].x,decal.pos[1].y,decal.z[1],1.f},{decal.pos[2].x,decal.pos[2].y,decal.z[2],1.f}},{{decal.uv[0].x,decal.uv[0].y,0.f},{decal.uv[1].x,decal.uv[1].y,0.f},{decal.uv[2].x,decal.uv[2].y,0.f}},{decal.tint[0],decal.tint[1],decal.tint[2]}}; + tri.p[0].z+=zIncrementer; + tri.p[1].z+=zIncrementer; + tri.p[2].z+=zIncrementer; renderer.Render({tri},decal.decal,GFX3D::RENDER_TEXTURED|GFX3D::RENDER_DEPTH); if(decal.z[0]>0.1f||decal.z[1]>0.1f||decal.z[2]>0.1f){ tri.col[0]=tri.col[1]=tri.col[2]={0,0,0,uint8_t(util::lerp(0,160,(1/std::pow(decal.z[0]/10.f+1,4))))}; - tri.p[0].z=tri.p[1].z=tri.p[2].z=0.1f; + tri.p[0].z=tri.p[1].z=tri.p[2].z=0.1f+zIncrementer; renderer.Render({tri},decal.decal,GFX3D::RENDER_TEXTURED|GFX3D::RENDER_DEPTH); } }else if(decal.points==4){ GFX3D::triangle tri{{{decal.pos[0].x,decal.pos[0].y,decal.z[0],1.f},{decal.pos[1].x,decal.pos[1].y,decal.z[1],1.f},{decal.pos[2].x,decal.pos[2].y,decal.z[2],1.f}},{{decal.uv[0].x,decal.uv[0].y,0.f},{decal.uv[1].x,decal.uv[1].y,0.f},{decal.uv[2].x,decal.uv[2].y,0.f}},{decal.tint[0],decal.tint[1],decal.tint[2]}}; GFX3D::triangle tri2{{{decal.pos[0].x,decal.pos[0].y,decal.z[0],1.f},{decal.pos[2].x,decal.pos[2].y,decal.z[2],1.f},{decal.pos[3].x,decal.pos[3].y,decal.z[3],1.f}},{{decal.uv[0].x,decal.uv[0].y,0.f},{decal.uv[2].x,decal.uv[2].y,0.f},{decal.uv[3].x,decal.uv[3].y,0.f}},{decal.tint[0],decal.tint[2],decal.tint[3]}}; + tri.p[0].z+=zIncrementer; + tri.p[1].z+=zIncrementer; + tri.p[2].z+=zIncrementer; + tri2.p[0].z+=zIncrementer; + tri2.p[1].z+=zIncrementer; + tri2.p[2].z+=zIncrementer; renderer.Render({tri,tri2},decal.decal,GFX3D::RENDER_TEXTURED|GFX3D::RENDER_DEPTH); if(decal.decal!=GetGFX("dot.png").Decal()&&(decal.z[0]>0.1f||decal.z[1]>0.1f||decal.z[2]>0.1f||decal.z[3]>0.1f)){ tri.col[0]=tri.col[1]=tri.col[2]=tri2.col[0]=tri2.col[1]=tri2.col[2]={0,0,0,uint8_t(util::lerp(0,160,(1/std::pow(decal.z[0]/10.f+1,4))))}; - tri.p[0].z=tri.p[1].z=tri.p[2].z=tri2.p[0].z=tri2.p[1].z=tri2.p[2].z=0.1f; + tri.p[0].z=tri.p[1].z=tri.p[2].z=tri2.p[0].z=tri2.p[1].z=tri2.p[2].z=0.1f+zIncrementer; renderer.Render({tri,tri2},decal.decal,GFX3D::RENDER_TEXTURED|GFX3D::RENDER_DEPTH); } }else{ @@ -462,10 +474,13 @@ void HamsterGame::Apply3DTransform(std::vector&decals){ if(decal.points%3!=0)throw std::runtime_error{std::format("WARNING! Number of decal structure points is not a multiple of 3! Points provided: {}. THIS SHOULD NOT BE HAPPENING!",decal.points)}; for(int i{0};i0||decal.z[i+1]>0||decal.z[i+2]>0){ + if(decal.z[i+0]>0.1f||decal.z[i+1]>0.1f||decal.z[i+2]>0.1f){ tri.col[0]=tri.col[1]=tri.col[2]={0,0,0,uint8_t(util::lerp(0,160,(1/std::pow(decal.z[0]/10.f+1,4))))}; - tri.p[0].z=tri.p[1].z=tri.p[2].z=0.1f; + tri.p[0].z=tri.p[1].z=tri.p[2].z=0.1f+zIncrementer; shadowTris.emplace_back(tri); } } @@ -475,6 +490,7 @@ void HamsterGame::Apply3DTransform(std::vector&decals){ } } SetDecalMode(DecalMode::NORMAL); + zIncrementer+=0.000001f; } std::sort(decals.begin(),decals.end(),[](const DecalInstance&d1,const DecalInstance&d2){return d1.z[0]>d2.z[0];}); @@ -533,22 +549,27 @@ void HamsterGame::DrawRadar(){ {HAMSTER,{{16.f*9,0.f},{16.f,16.f}}}, }; + const auto DeferRenderingBasedOnPosition=[this,&icon](const vf2d&pos,const IconType powerupIcon,const uint8_t iconAlpha){ + if(geom2d::intersects(geom2d::circle{{43.f+5.f,44.f+8.f},43},geom2d::rect{pos-vf2d{16.f,16.f},{32.f,32.f}}).size()>0)radar.DrawPartialRotatedDecal(pos,GetGFX("radaricons.png").Decal(),0.f,{8.f,8.f},icon.at(powerupIcon).pos,icon.at(powerupIcon).size,{1.f,1.f},{255,255,255,iconAlpha}); + else if(geom2d::contains(geom2d::circle{{43.f+5.f,44.f+8.f},43},geom2d::rect{pos-vf2d{8.f,8.f},{16.f,16.f}}))DrawPartialRotatedDecal(pos+vf2d{5.f,8.f},GetGFX("radaricons.png").Decal(),0.f,{8.f,8.f},icon.at(powerupIcon).pos,icon.at(powerupIcon).size,{1.f,1.f},{255,255,255,iconAlpha}); + }; + for(const Powerup&powerup:Powerup::GetPowerups()){ IconType powerupIcon{IconType(int(powerup.GetType())+1)}; uint8_t iconAlpha{255U}; if(Hamster::GetPlayer().HasPowerup(powerup.GetType()))iconAlpha=64U; - radar.DrawPartialRotatedDecal(WorldToRadar(powerup.GetPos()),GetGFX("radaricons.png").Decal(),0.f,{8.f,8.f},icon.at(powerupIcon).pos,icon.at(powerupIcon).size,{1.f,1.f},{255,255,255,iconAlpha}); + DeferRenderingBasedOnPosition(WorldToRadar(powerup.GetPos()),powerupIcon,iconAlpha); } for(const Checkpoint&cp:Checkpoint::GetCheckpoints()){ uint8_t iconAlpha{255U}; if(Hamster::GetPlayer().HasCollectedCheckpoint(cp))iconAlpha=64U; - radar.DrawPartialRotatedDecal(WorldToRadar(cp.GetPos()),GetGFX("radaricons.png").Decal(),0.f,{8.f,8.f},icon.at(CHECKPOINT).pos,icon.at(CHECKPOINT).size,{1.f,1.f},{255,255,255,iconAlpha}); + DeferRenderingBasedOnPosition(WorldToRadar(cp.GetPos()),CHECKPOINT,iconAlpha); } for(const Hamster&h:Hamster::GetHamsters()){ if(&h==&Hamster::GetPlayer())continue; uint8_t iconAlpha{255U}; if(h.BurnedOrDrowned())iconAlpha=64U; - radar.DrawPartialRotatedDecal(WorldToRadar(h.GetPos()),GetGFX("radaricons.png").Decal(),0.f,{8.f,8.f},icon.at(HAMSTER).pos,icon.at(HAMSTER).size,{1.f,1.f},{255,255,255,iconAlpha}); + DeferRenderingBasedOnPosition(WorldToRadar(h.GetPos()),HAMSTER,iconAlpha); } } diff --git a/src/HamsterJet.cpp b/src/HamsterJet.cpp index be08f20..aa30394 100644 --- a/src/HamsterJet.cpp +++ b/src/HamsterJet.cpp @@ -52,10 +52,14 @@ void HamsterJet::Update(const float fElapsedTime){ lastTappedSpace+=fElapsedTime; switch(state){ case SWOOP_DOWN:{ - HamsterGame::Game().SetZoom(1.5f); + if(hamster.IsPlayerControlled)HamsterGame::Game().SetZoom(1.5f); z=util::lerp(0.f,3.f,std::pow(timer/3.f,2)); vf2d originalPos{hamster.GetPos().x-128.f,hamster.GetPos().y+32.f}; if(timer<=0.4f){ + if(!setHamsterOriginalPos){ + setHamsterOriginalPos=true; + hamsterOriginalPos=hamster.GetPos(); + } hamster.SetPos(hamsterOriginalPos-vf2d{0.f,sin(float(geom2d::pi)*timer/0.4f)*8.f}); hamster.SetZ(sin(float(geom2d::pi)*timer/0.4f)*0.2f); jetState[TOP_LEFT]=jetState[BOTTOM_LEFT]=jetState[BOTTOM_RIGHT]=jetState[TOP_RIGHT]=OFF; @@ -80,21 +84,28 @@ void HamsterJet::Update(const float fElapsedTime){ hamster.SetZ(z+0.03f); if(timer<=0.f){ state=HAMSTER_CONTROL; - HamsterGame::Game().SetZoom(0.6f); + if(hamster.IsPlayerControlled)HamsterGame::Game().SetZoom(0.6f); easeInTimer=0.6f; } }break; case HAMSTER_CONTROL:{ easeInTimer=std::max(0.f,easeInTimer-fElapsedTime); jetState[TOP_LEFT]=jetState[BOTTOM_LEFT]=jetState[BOTTOM_RIGHT]=jetState[TOP_RIGHT]=OFF; - HandleJetControls(); + if(hamster.CanMove()){ + if(hamster.IsPlayerControlled)HandleJetControls(); + else{ + //TODO: AI controls here! + } + } }break; case LANDING:{ easeInTimer=std::min(0.6f,easeInTimer+fElapsedTime); jetState[TOP_LEFT]=jetState[BOTTOM_LEFT]=jetState[BOTTOM_RIGHT]=jetState[TOP_RIGHT]=OFF; - if(hamster.IsPlayerControlled)HandleJetControls(); - else{ - //TODO: AI controls here! + if(hamster.CanMove()){ + if(hamster.IsPlayerControlled)HandleJetControls(); + else{ + //TODO: AI controls here! + } } pos=hamster.GetPos(); hamster.SetZ(hamster.GetZ()-fallSpd*fElapsedTime); @@ -103,7 +114,7 @@ void HamsterJet::Update(const float fElapsedTime){ hamster.SetZ(0.f); state=COMPLETE_LANDING; hamster.SetState(Hamster::NORMAL); - HamsterGame::Game().SetZoom(1.f); + if(hamster.IsPlayerControlled)HamsterGame::Game().SetZoom(1.f); timer=3.f; originalPos=hamster.GetPos(); targetPos={hamster.GetPos().x+128.f,hamster.GetPos().y+32.f}; @@ -220,4 +231,8 @@ Terrain::CrashSpeed HamsterJet::GetLandingSpeed()const{ if(fallSpd>4.f)return Terrain::MAX; if(fallSpd>2.f)return Terrain::MEDIUM; else return Terrain::LIGHT; +} + +const float HamsterJet::GetZ()const{ + return z; } \ No newline at end of file diff --git a/src/HamsterJet.h b/src/HamsterJet.h index 97757db..5125ebe 100644 --- a/src/HamsterJet.h +++ b/src/HamsterJet.h @@ -39,11 +39,9 @@ All rights reserved. #include "olcUTIL_Geometry2D.h" #include "SpecialRenderable.h" +#include "Terrain.h" class Hamster; -namespace Terrain{ - enum CrashSpeed; -}; class HamsterJet{ public: @@ -80,6 +78,7 @@ private: float timer{}; std::arrayjetState{}; float lastTappedSpace{}; + bool setHamsterOriginalPos{false}; public: HamsterJet(Hamster&hamster); void Update(const float fElapsedTime); @@ -89,4 +88,5 @@ public: const State GetState()const; void SetPos(const vf2d pos); Terrain::CrashSpeed GetLandingSpeed()const; + const float GetZ()const; }; \ No newline at end of file diff --git a/src/olcPGEX_Graphics3D.h b/src/olcPGEX_Graphics3D.h index 7525d0c..d05de53 100644 --- a/src/olcPGEX_Graphics3D.h +++ b/src/olcPGEX_Graphics3D.h @@ -976,221 +976,90 @@ namespace olc line2 = GFX3D::Math::Vec_Sub(triTransformed.p[2], triTransformed.p[0]); normal = GFX3D::Math::Vec_CrossProduct(line1, line2); normal = GFX3D::Math::Vec_Normalise(normal); - - // Cull triangles that face away from viewer - if (flags & RENDER_CULL_CW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) > 0.0f) continue; - if (flags & RENDER_CULL_CCW && GFX3D::Math::Vec_DotProduct(normal, triTransformed.p[0]) < 0.0f) continue; - - // If Lighting, calculate shading - if (flags & RENDER_LIGHTS) + triangle triProjected = triTransformed; + + // Project new triangle + triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, triTransformed.p[0]); + triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, triTransformed.p[1]); + triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, triTransformed.p[2]); + + // Apply Projection to Verts + triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; + triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; + triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; + + triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; + triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; + triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; + + triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; + triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; + triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; + + // Apply Projection to Tex coords + triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; + triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; + triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; + + triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; + triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; + triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; + + triProjected.t[0].z = 1.0f / triProjected.p[0].w; + triProjected.t[1].z = 1.0f / triProjected.p[1].w; + triProjected.t[2].z = 1.0f / triProjected.p[2].w; + // Scale to viewport + /*triRaster.p[0].x *= -1.0f; + triRaster.p[1].x *= -1.0f; + triRaster.p[2].x *= -1.0f; + triRaster.p[0].y *= -1.0f; + triRaster.p[1].y *= -1.0f; + triTransformed.p[2].y *= -1.0f;*/ + vec3d vOffsetView = { 1,1,0 }; + triProjected.p[0] = Math::Vec_Add(triProjected.p[0], vOffsetView); + triProjected.p[1] = Math::Vec_Add(triProjected.p[1], vOffsetView); + triProjected.p[2] = Math::Vec_Add(triProjected.p[2], vOffsetView); + triProjected.p[0].x *= 0.5f * fViewW; + triProjected.p[0].y *= 0.5f * fViewH; + triProjected.p[1].x *= 0.5f * fViewW; + triProjected.p[1].y *= 0.5f * fViewH; + triProjected.p[2].x *= 0.5f * fViewW; + triProjected.p[2].y *= 0.5f * fViewH; + vOffsetView = { fViewX,fViewY,0 }; + triProjected.p[0] = Math::Vec_Add(triProjected.p[0], vOffsetView); + triProjected.p[1] = Math::Vec_Add(triProjected.p[1], vOffsetView); + triProjected.p[2] = Math::Vec_Add(triProjected.p[2], vOffsetView); + + // For now, just draw triangle + + //if (flags & RENDER_TEXTURED) + //{/* + // TexturedTriangle( + // triProjected.p[0].x, triProjected.p[0].y, triProjected.t[0].x, triProjected.t[0].y, triProjected.t[0].z, + // triProjected.p[1].x, triProjected.p[1].y, triProjected.t[1].x, triProjected.t[1].y, triProjected.t[1].z, + // triProjected.p[2].x, triProjected.p[2].y, triProjected.t[2].x, triProjected.t[2].y, triProjected.t[2].z, + // sprTexture);*/ + + // RasterTriangle( + // triProjected.p[0].x, triProjected.p[0].y, triProjected.t[0].x, triProjected.t[0].y, triProjected.t[0].z, triProjected.col, + // triProjected.p[1].x, triProjected.p[1].y, triProjected.t[1].x, triProjected.t[1].y, triProjected.t[1].z, triProjected.col, + // triProjected.p[2].x, triProjected.p[2].y, triProjected.t[2].x, triProjected.t[2].y, triProjected.t[2].z, triProjected.col, + // sprTexture, nFlags); + + //} + + if (flags & RENDER_WIRE) { - olc::Pixel ambient_clamp = { 0,0,0 }; - olc::Pixel light_combined = { 0,0,0 }; - uint32_t nLightSources = 0; - float nLightR = 0, nLightG = 0, nLightB = 0; - - for (int i = 0; i < 4; i++) - { - switch (lights[i].type) - { - case LIGHT_DISABLED: - break; - case LIGHT_AMBIENT: - ambient_clamp = lights[i].col; - break; - case LIGHT_DIRECTIONAL: - { - nLightSources++; - GFX3D::vec3d light_dir = GFX3D::Math::Vec_Normalise(lights[i].dir); - float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); - if (light > 0) - { - int j = 0; - } - - light = std::max(light, 0.0f); - nLightR += light * (lights[i].col.r/255.0f); - nLightG += light * (lights[i].col.g/255.0f); - nLightB += light * (lights[i].col.b/255.0f); - } - break; - case LIGHT_POINT: - break; - } - } - - //nLightR /= nLightSources; - //nLightG /= nLightSources; - //nLightB /= nLightSources; - - nLightR = std::max(nLightR, ambient_clamp.r / 255.0f); - nLightG = std::max(nLightG, ambient_clamp.g / 255.0f); - nLightB = std::max(nLightB, ambient_clamp.b / 255.0f); - - triTransformed.col[0] = olc::Pixel(uint8_t(nLightR * triTransformed.col[0].r), uint8_t(nLightG * triTransformed.col[0].g), uint8_t(nLightB * triTransformed.col[0].b)); - triTransformed.col[1] = olc::Pixel(uint8_t(nLightR * triTransformed.col[1].r), uint8_t(nLightG * triTransformed.col[1].g), uint8_t(nLightB * triTransformed.col[1].b)); - triTransformed.col[2] = olc::Pixel(uint8_t(nLightR * triTransformed.col[2].r), uint8_t(nLightG * triTransformed.col[2].g), uint8_t(nLightB * triTransformed.col[2].b)); - - - - /*GFX3D::vec3d light_dir = { 1,1,1 }; - light_dir = GFX3D::Math::Vec_Normalise(light_dir); - float light = GFX3D::Math::Vec_DotProduct(light_dir, normal); - if (light < 0) light = 0; - triTransformed.col[0] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); - triTransformed.col[1] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f); - triTransformed.col[2] = olc::Pixel(light * 255.0f, light * 255.0f, light * 255.0f);*/ + DrawTriangleWire(triProjected, olc::RED); } - //else - // triTransformed.col = olc::WHITE; - - // Clip triangle against near plane - int nClippedTriangles = 0; - GFX3D::triangle clipped[2]; - nClippedTriangles = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, 0.0f, 0.1f }, { 0.0f, 0.0f, 1.0f }, triTransformed, clipped[0], clipped[1]); - - // This may yield two new triangles - for (int n = 0; n < nClippedTriangles; n++) + else { - triangle triProjected = clipped[n]; - - // Project new triangle - triProjected.p[0] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[0]); - triProjected.p[1] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[1]); - triProjected.p[2] = GFX3D::Math::Mat_MultiplyVector(matProj, clipped[n].p[2]); - - // Apply Projection to Verts - triProjected.p[0].x = triProjected.p[0].x / triProjected.p[0].w; - triProjected.p[1].x = triProjected.p[1].x / triProjected.p[1].w; - triProjected.p[2].x = triProjected.p[2].x / triProjected.p[2].w; - - triProjected.p[0].y = triProjected.p[0].y / triProjected.p[0].w; - triProjected.p[1].y = triProjected.p[1].y / triProjected.p[1].w; - triProjected.p[2].y = triProjected.p[2].y / triProjected.p[2].w; - - triProjected.p[0].z = triProjected.p[0].z / triProjected.p[0].w; - triProjected.p[1].z = triProjected.p[1].z / triProjected.p[1].w; - triProjected.p[2].z = triProjected.p[2].z / triProjected.p[2].w; - - // Apply Projection to Tex coords - triProjected.t[0].x = triProjected.t[0].x / triProjected.p[0].w; - triProjected.t[1].x = triProjected.t[1].x / triProjected.p[1].w; - triProjected.t[2].x = triProjected.t[2].x / triProjected.p[2].w; - - triProjected.t[0].y = triProjected.t[0].y / triProjected.p[0].w; - triProjected.t[1].y = triProjected.t[1].y / triProjected.p[1].w; - triProjected.t[2].y = triProjected.t[2].y / triProjected.p[2].w; - - triProjected.t[0].z = 1.0f / triProjected.p[0].w; - triProjected.t[1].z = 1.0f / triProjected.p[1].w; - triProjected.t[2].z = 1.0f / triProjected.p[2].w; - - // Clip against viewport in screen space - // Clip triangles against all four screen edges, this could yield - // a bunch of triangles, so create a queue that we traverse to - // ensure we only test new triangles generated against planes - GFX3D::triangle sclipped[2]; - std::list listTriangles; - - - // Add initial triangle - listTriangles.push_back(triProjected); - int nNewTriangles = 1; - - for (int p = 0; p < 4; p++) - { - int nTrisToAdd = 0; - while (nNewTriangles > 0) - { - // Take triangle from front of queue - triangle test = listTriangles.front(); - listTriangles.pop_front(); - nNewTriangles--; - - // Clip it against a plane. We only need to test each - // subsequent plane, against subsequent new triangles - // as all triangles after a plane clip are guaranteed - // to lie on the inside of the plane. I like how this - // comment is almost completely and utterly justified - switch (p) - { - case 0: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, -1.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 1: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ 0.0f, +1.0f, 0.0f }, { 0.0f, -1.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 2: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ -1.0f, 0.0f, 0.0f }, { 1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - case 3: nTrisToAdd = GFX3D::Math::Triangle_ClipAgainstPlane({ +1.0f, 0.0f, 0.0f }, { -1.0f, 0.0f, 0.0f }, test, sclipped[0], sclipped[1]); break; - } - - - // Clipping may yield a variable number of triangles, so - // add these new ones to the back of the queue for subsequent - // clipping against next planes - for (int w = 0; w < nTrisToAdd; w++) - listTriangles.push_back(sclipped[w]); - } - nNewTriangles = listTriangles.size(); - } - - for (auto &triRaster : listTriangles) - { - // Scale to viewport - /*triRaster.p[0].x *= -1.0f; - triRaster.p[1].x *= -1.0f; - triRaster.p[2].x *= -1.0f; - triRaster.p[0].y *= -1.0f; - triRaster.p[1].y *= -1.0f; - triRaster.p[2].y *= -1.0f;*/ - vec3d vOffsetView = { 1,1,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - triRaster.p[0].x *= 0.5f * fViewW; - triRaster.p[0].y *= 0.5f * fViewH; - triRaster.p[1].x *= 0.5f * fViewW; - triRaster.p[1].y *= 0.5f * fViewH; - triRaster.p[2].x *= 0.5f * fViewW; - triRaster.p[2].y *= 0.5f * fViewH; - vOffsetView = { fViewX,fViewY,0 }; - triRaster.p[0] = Math::Vec_Add(triRaster.p[0], vOffsetView); - triRaster.p[1] = Math::Vec_Add(triRaster.p[1], vOffsetView); - triRaster.p[2] = Math::Vec_Add(triRaster.p[2], vOffsetView); - - // For now, just draw triangle - - //if (flags & RENDER_TEXTURED) - //{/* - // TexturedTriangle( - // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, - // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, - // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, - // sprTexture);*/ - - // RasterTriangle( - // triRaster.p[0].x, triRaster.p[0].y, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col, - // triRaster.p[1].x, triRaster.p[1].y, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col, - // triRaster.p[2].x, triRaster.p[2].y, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col, - // sprTexture, nFlags); - - //} - - if (flags & RENDER_WIRE) - { - DrawTriangleWire(triRaster, olc::RED); - } - else - { - RasterTriangle( - triRaster.p[0].x,triRaster.p[0].y,triRaster.p[0].z, triRaster.t[0].x, triRaster.t[0].y, triRaster.t[0].z, triRaster.col[0], - triRaster.p[1].x,triRaster.p[1].y,triRaster.p[1].z, triRaster.t[1].x, triRaster.t[1].y, triRaster.t[1].z, triRaster.col[1], - triRaster.p[2].x,triRaster.p[2].y,triRaster.p[2].z, triRaster.t[2].x, triRaster.t[2].y, triRaster.t[2].z, triRaster.col[2], - dec, flags); + RasterTriangle( + triProjected.p[0].x,triProjected.p[0].y,triProjected.p[0].z, triProjected.t[0].x, triProjected.t[0].y, triProjected.t[0].z, triProjected.col[0], + triProjected.p[1].x,triProjected.p[1].y,triProjected.p[1].z, triProjected.t[1].x, triProjected.t[1].y, triProjected.t[1].z, triProjected.col[1], + triProjected.p[2].x,triProjected.p[2].y,triProjected.p[2].z, triProjected.t[2].x, triProjected.t[2].y, triProjected.t[2].z, triProjected.col[2], + dec, flags); - } - - - - - nTriangleDrawnCount++; - } } } diff --git a/src/olcPGEX_Viewport.h b/src/olcPGEX_Viewport.h index b179eca..f9e7b30 100644 --- a/src/olcPGEX_Viewport.h +++ b/src/olcPGEX_Viewport.h @@ -156,7 +156,7 @@ olc::ViewPort::ViewPort(std::vector vertices, olc::vf2d offset) } void olc::ViewPort::addPoint(vf2d point) { - clipVertices.push_back(point); + clipVertices.emplace_back(point); } void olc::ViewPort::clear() { @@ -600,17 +600,17 @@ void olc::ViewPort::drawClippedDecal(Decal *decal, if (bDirection <= 0) { if (aDirection > 0) { - outputList.push_back(intersectionPoint); - outputUvs.push_back(intersectionUv); - outputCols.push_back(intersectionCol); + outputList.emplace_back(intersectionPoint); + outputUvs.emplace_back(intersectionUv); + outputCols.emplace_back(intersectionCol); } - outputList.push_back(polygonB); - outputUvs.push_back(uvB); - outputCols.push_back(colB); + outputList.emplace_back(polygonB); + outputUvs.emplace_back(uvB); + outputCols.emplace_back(colB); } else if (aDirection <= 0) { - outputList.push_back(intersectionPoint); - outputUvs.push_back(intersectionUv); - outputCols.push_back(intersectionCol); + outputList.emplace_back(intersectionPoint); + outputUvs.emplace_back(intersectionUv); + outputCols.emplace_back(intersectionCol); } } } @@ -670,17 +670,17 @@ void olc::ViewPort::drawClippedPolygonDecal(Decal *decal, if (bDirection <= 0) { if (aDirection > 0) { - outputList.push_back(intersectionPoint); - outputUvs.push_back(intersectionUv); - outputDepths.push_back(intersectionDepth); + outputList.emplace_back(intersectionPoint); + outputUvs.emplace_back(intersectionUv); + outputDepths.emplace_back(intersectionDepth); } - outputList.push_back(polygonB); - outputUvs.push_back(uvB); - outputDepths.push_back(Wb); + outputList.emplace_back(polygonB); + outputUvs.emplace_back(uvB); + outputDepths.emplace_back(Wb); } else if (aDirection <= 0) { - outputList.push_back(intersectionPoint); - outputUvs.push_back(intersectionUv); - outputDepths.push_back(intersectionDepth); + outputList.emplace_back(intersectionPoint); + outputUvs.emplace_back(intersectionUv); + outputDepths.emplace_back(intersectionDepth); } } } diff --git a/src/olcPixelGameEngine.h b/src/olcPixelGameEngine.h index 54155ac..fd3c6a7 100644 --- a/src/olcPixelGameEngine.h +++ b/src/olcPixelGameEngine.h @@ -3272,7 +3272,7 @@ namespace olc { DecalInstance di; di.decal = decal; - di.points = 4; + di.points = 4; di.tint = { tint, tint, tint, tint }; di.w = { 1, 1, 1, 1 }; di.z={z,z,z,z}; @@ -4596,26 +4596,12 @@ namespace olc glBegin(GL_TRIANGLES); } - if (decal.depth) + // Render as 2D Spatial entity + for (uint32_t n = 0; n < decal.points; n++) { - - // Render as 3D Spatial Entity - for (uint32_t n = 0; n < decal.points; n++) - { - glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); - glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]); - glVertex3f(decal.pos[n].x, decal.pos[n].y, decal.z[n]); - } - } - else - { - // Render as 2D Spatial entity - for (uint32_t n = 0; n < decal.points; n++) - { - glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); - glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]); - glVertex2f(decal.pos[n].x, decal.pos[n].y); - } + glColor4ub(decal.tint[n].r, decal.tint[n].g, decal.tint[n].b, decal.tint[n].a); + glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]); + glVertex2f(decal.pos[n].x, decal.pos[n].y); } glEnd();