Lots of micro-optimizations and depth fixes for emscripten.

sigonasr2 5 months ago
parent 14296e2e63
commit 599114ca02
  1. 3
      src/Checkpoint.cpp
  2. 3
      src/FloatingText.cpp
  3. 35
      src/Hamster.cpp
  4. 2
      src/Hamster.h
  5. 47
      src/HamsterGame.cpp
  6. 23
      src/HamsterJet.cpp
  7. 6
      src/HamsterJet.h
  8. 185
      src/olcPGEX_Graphics3D.h
  9. 38
      src/olcPGEX_Viewport.h
  10. 14
      src/olcPixelGameEngine.h

@ -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::line<float>playerToCheckpointLine{geom2d::line<float>(Hamster::GetPlayer().GetPos(),checkpoint.pos)};

@ -73,12 +73,13 @@ void FloatingText::Draw(TransformedView&tv){
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);
}

@ -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;
}
@ -589,3 +597,10 @@ 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;
}

@ -162,4 +162,6 @@ public:
static const std::vector<Hamster>&GetHamsters();
const HamsterState&GetState()const;
const bool BurnedOrDrowned()const;
const bool CanMove()const;
const bool FlyingInTheAir()const;
};

@ -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::vector<vf2d>radarCircle;
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<AnimationState::AnimationState>&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<DecalInstance>&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<DecalInstance>&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};i<decal.points;i+=3){
GFX3D::triangle tri{{{decal.pos[i+0].x,decal.pos[i+0].y,decal.z[i+0],1.f},{decal.pos[i+1].x,decal.pos[i+1].y,decal.z[i+1],1.f},{decal.pos[i+2].x,decal.pos[i+2].y,decal.z[i+2],1.f}},{{decal.uv[i+0].x,decal.uv[i+0].y,0.f},{decal.uv[i+1].x,decal.uv[i+1].y,0.f},{decal.uv[i+2].x,decal.uv[i+2].y,0.f}},{decal.tint[i+0],decal.tint[i+1],decal.tint[i+2]}};
tri.p[0].z+=zIncrementer;
tri.p[1].z+=zIncrementer;
tri.p[2].z+=zIncrementer;
tris.emplace_back(tri);
if(decal.z[i+0]>0||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<DecalInstance>&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<float>{{43.f+5.f,44.f+8.f},43},geom2d::rect<float>{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<float>{{43.f+5.f,44.f+8.f},43},geom2d::rect<float>{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);
}
}

@ -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,22 +84,29 @@ 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.CanMove()){
if(hamster.IsPlayerControlled)HandleJetControls();
else{
//TODO: AI controls here!
}
}
pos=hamster.GetPos();
hamster.SetZ(hamster.GetZ()-fallSpd*fElapsedTime);
z=hamster.GetZ();
@ -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};
@ -221,3 +232,7 @@ Terrain::CrashSpeed HamsterJet::GetLandingSpeed()const{
if(fallSpd>2.f)return Terrain::MEDIUM;
else return Terrain::LIGHT;
}
const float HamsterJet::GetZ()const{
return z;
}

@ -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::array<JetState,4>jetState{};
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;
};

@ -976,88 +976,12 @@ 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)
{
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);*/
}
//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++)
{
triangle triProjected = clipped[n];
triangle triProjected = triTransformed;
// 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]);
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;
@ -1084,114 +1008,59 @@ namespace olc
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<GFX3D::triangle> 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;*/
triTransformed.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;
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 };
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);
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(
// 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,
// 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(
// 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,
// 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)
{
DrawTriangleWire(triRaster, olc::RED);
DrawTriangleWire(triProjected, 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],
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++;
}
}
}
return nTriangleDrawnCount;

@ -156,7 +156,7 @@ olc::ViewPort::ViewPort(std::vector<vf2d> 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);
}
}
}

@ -4596,19 +4596,6 @@ namespace olc
glBegin(GL_TRIANGLES);
}
if (decal.depth)
{
// 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++)
{
@ -4616,7 +4603,6 @@ namespace olc
glTexCoord4f(decal.uv[n].x, decal.uv[n].y, 0.0f, decal.w[n]);
glVertex2f(decal.pos[n].x, decal.pos[n].y);
}
}
glEnd();

Loading…
Cancel
Save