Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Darken background drawing to improve player/enemy/item visibility #882

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions src/data/game_options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ namespace rigel::data
constexpr auto ENABLE_VSYNC_DEFAULT = true;
constexpr auto MUSIC_VOLUME_DEFAULT = 1.0f;
constexpr auto SOUND_VOLUME_DEFAULT = 1.0f;
constexpr auto FOREGROUND_SPRITE_BRIGHTNESS_DEFAULT = 1.0f;
constexpr auto REGULAR_SPRITE_BRIGHTNESS_DEFAULT = 1.0f;
constexpr auto BACKGROUND_SPRITE_BRIGHTNESS_DEFAULT = 1.0f;
constexpr auto FOREGROUND_TILE_BRIGHTNESS_DEFAULT = 1.0f;
constexpr auto BACKGROUND_TILE_BRIGHTNESS_DEFAULT = 1.0f;
constexpr auto BACKDROP_TILE_BRIGHTNESS_DEFAULT = 1.0f;

enum class WindowMode
{
Expand Down Expand Up @@ -156,6 +162,13 @@ struct GameOptions
bool mQuickSavingEnabled = false;
bool mSkipIntro = false;
bool mMotionSmoothing = false;
float mForeSpriteBrightness = FOREGROUND_SPRITE_BRIGHTNESS_DEFAULT;
float mRegSpriteBrightness = REGULAR_SPRITE_BRIGHTNESS_DEFAULT;
float mBackSpriteBrightness = BACKGROUND_SPRITE_BRIGHTNESS_DEFAULT;
bool mPrisonerIsBackground = false;
float mForeTileBrightness = FOREGROUND_TILE_BRIGHTNESS_DEFAULT;
float mBackTileBrightness = BACKGROUND_TILE_BRIGHTNESS_DEFAULT;
float mDropTileBrightness = BACKDROP_TILE_BRIGHTNESS_DEFAULT;

// Internal options
//
Expand Down
57 changes: 45 additions & 12 deletions src/engine/sprite_rendering_system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ void collectVisibleSprites(
using components::DrawTopMost;
using components::ExtendedFrameList;
using components::OverrideDrawOrder;
using components::SpriteBackground;
using components::SpriteStrip;

const auto screenBox = BoundingBox{{}, viewportSize};
Expand All @@ -99,7 +100,8 @@ void collectVisibleSprites(
const bool flashingWhite,
const bool useCloakEffect,
const bool drawTopmost,
const int drawOrder) {
const int drawOrder,
const bool background) {
const auto topLeft = drawPosition(frame, position);

// Discard sprites outside visible area
Expand All @@ -115,8 +117,8 @@ void collectVisibleSprites(
engine::interpolatedPixelPosition(
previousTopLeft, topLeft, interpolationFactor),
data::tilesToPixels(frame.mDimensions)};
const auto drawSpec =
SpriteDrawSpec{destRect, frame.mImageId, flashingWhite, useCloakEffect};
const auto drawSpec = SpriteDrawSpec{
destRect, frame.mImageId, flashingWhite, useCloakEffect, background};

output.push_back({drawSpec, drawOrder, drawTopmost});
};
Expand All @@ -138,6 +140,7 @@ void collectVisibleSprites(
const auto drawOrder = entity.has_component<OverrideDrawOrder>()
? entity.component<const OverrideDrawOrder>()->mDrawOrder
: sprite.mpDrawData->mDrawOrder;
const auto background = entity.has_component<SpriteBackground>();

auto slotIndex = 0;
for (const auto& baseFrameIndex : sprite.mFramesToRender)
Expand All @@ -158,7 +161,10 @@ void collectVisibleSprites(
sprite.mFlashingWhiteStates.test(slotIndex),
sprite.mUseCloakEffect,
drawTopmost,
drawOrder);
drawOrder,
background &&
entity.component<SpriteBackground>()->mRenderSlotMask.test(
slotIndex));
++slotIndex;
}

Expand All @@ -177,7 +183,8 @@ void collectVisibleSprites(
false,
sprite.mUseCloakEffect,
drawTopmost,
drawOrder);
drawOrder,
background);
}
}

Expand Down Expand Up @@ -210,8 +217,8 @@ void collectVisibleSprites(
base::Rect<int>{data::tilesToPixels(topLeft), {width, height}};

const auto useCloakEffect = sprite.mUseCloakEffect;
const auto drawSpec =
SpriteDrawSpec{destRect, frame.mImageId, false, useCloakEffect};
const auto drawSpec = SpriteDrawSpec{
destRect, frame.mImageId, false, useCloakEffect, background};
output.push_back({drawSpec, drawOrder, drawTopmost});
}
});
Expand Down Expand Up @@ -354,29 +361,45 @@ void SpriteRenderingSystem::update(
}


void SpriteRenderingSystem::renderBackgroundSprites(
const SpecialEffectsRenderer& fx,
const float backColorMod) const
{
for (auto it = mSprites.begin(); it != miForegroundSprites; ++it)
{
if (it->mBackground)
renderSprite(*it, fx, backColorMod);
}
}


void SpriteRenderingSystem::renderRegularSprites(
const SpecialEffectsRenderer& fx) const
const SpecialEffectsRenderer& fx,
const float regColorMod) const
{
for (auto it = mSprites.begin(); it != miForegroundSprites; ++it)
{
renderSprite(*it, fx);
if (!(it->mBackground))
renderSprite(*it, fx, regColorMod);
}
}


void SpriteRenderingSystem::renderForegroundSprites(
const SpecialEffectsRenderer& fx) const
const SpecialEffectsRenderer& fx,
const float foreColorMod) const
{
for (auto it = miForegroundSprites; it != mSprites.end(); ++it)
{
renderSprite(*it, fx);
renderSprite(*it, fx, foreColorMod);
}
}


void SpriteRenderingSystem::renderSprite(
const SpriteDrawSpec& spec,
const SpecialEffectsRenderer& fx) const
const SpecialEffectsRenderer& fx,
const float colorMod) const
{
// White flash takes priority over translucency
if (spec.mIsFlashingWhite)
Expand All @@ -393,7 +416,17 @@ void SpriteRenderingSystem::renderSprite(
}
else
{
if (colorMod < 1.0f)
{
// const auto saved = renderer::saveState(mpRenderer);
mpRenderer->setColorModulation(base::Color{
base::roundTo<uint8_t, float>(255 * colorMod),
base::roundTo<uint8_t, float>(255 * colorMod),
base::roundTo<uint8_t, float>(255 * colorMod),
255});
}
mpTextureAtlas->draw(spec.mImageId, spec.mDestRect);
mpRenderer->setColorModulation(base::Color{255, 255, 255, 255});
}
}

Expand Down
15 changes: 12 additions & 3 deletions src/engine/sprite_rendering_system.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ struct SpriteDrawSpec
int mImageId;
bool mIsFlashingWhite;
bool mUseCloakEffect;
bool mBackground;
};


Expand Down Expand Up @@ -90,13 +91,21 @@ class SpriteRenderingSystem

bool cloakEffectSpritesVisible() const { return mCloakEffectSpritesVisible; }

void renderRegularSprites(const SpecialEffectsRenderer& fx) const;
void renderForegroundSprites(const SpecialEffectsRenderer& fx) const;
void renderBackgroundSprites(
const SpecialEffectsRenderer& fx,
const float backColorMod) const;
void renderRegularSprites(
const SpecialEffectsRenderer& fx,
const float regColorMod) const;
void renderForegroundSprites(
const SpecialEffectsRenderer& fx,
const float foreColorMod) const;

private:
void renderSprite(
const SpriteDrawSpec& spec,
const SpecialEffectsRenderer& fx) const;
const SpecialEffectsRenderer& fx,
const float colorMod) const;

// Temporary storage used for sorting sprites by draw order during sprite
// collection. Scope-wise, this is only needed during update(), but in order
Expand Down
12 changes: 12 additions & 0 deletions src/engine/visual_components.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,18 @@ struct ExtendedFrameList
};


struct SpriteBackground
{
SpriteBackground()
{
// Apply to all render slots by default
mRenderSlotMask.set();
}

std::bitset<NUM_RENDER_SLOTS> mRenderSlotMask;
};


struct SpriteStrip
{
explicit SpriteStrip(const base::Vec2& start, int frame)
Expand Down
21 changes: 21 additions & 0 deletions src/frontend/user_profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,13 @@ nlohmann::ordered_json serialize(const data::GameOptions& options)
serialized["quickSavingEnabled"] = options.mQuickSavingEnabled;
serialized["skipIntro"] = options.mSkipIntro;
serialized["motionSmoothing"] = options.mMotionSmoothing;
serialized["foregroundSpriteBrightness"] = options.mForeSpriteBrightness;
serialized["regularSpriteBrightness"] = options.mRegSpriteBrightness;
serialized["backgroundSpriteBrightness"] = options.mBackSpriteBrightness;
serialized["prisonerIsBackground"] = options.mPrisonerIsBackground;
serialized["foregroundTileBrightness"] = options.mForeTileBrightness;
serialized["backgroundTileBrightness"] = options.mBackTileBrightness;
serialized["parallaxTileBrightness"] = options.mDropTileBrightness;
return serialized;
}

Expand Down Expand Up @@ -661,6 +668,20 @@ data::GameOptions deserialize<data::GameOptions>(const nlohmann::json& json)
extractValueIfExists("quickSavingEnabled", result.mQuickSavingEnabled, json);
extractValueIfExists("skipIntro", result.mSkipIntro, json);
extractValueIfExists("motionSmoothing", result.mMotionSmoothing, json);
extractValueIfExists(
"foregroundSpriteBrightness", result.mForeSpriteBrightness, json);
extractValueIfExists(
"regularSpriteBrightness", result.mRegSpriteBrightness, json);
extractValueIfExists(
"backgroundSpriteBrightness", result.mBackSpriteBrightness, json);
extractValueIfExists(
"prisonerIsBackground", result.mPrisonerIsBackground, json);
extractValueIfExists(
"foregroundTileBrightness", result.mForeTileBrightness, json);
extractValueIfExists(
"backgroundTileBrightness", result.mBackTileBrightness, json);
extractValueIfExists(
"parallaxTileBrightness", result.mDropTileBrightness, json);

removeInvalidKeybindings(result);

Expand Down
13 changes: 13 additions & 0 deletions src/game_logic/entity_configuration.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,13 +1669,24 @@ void EntityFactory::configureEntity(
entity.component<Shootable>()->mInvincible = true;
entity.component<Shootable>()->mDestroyWhenKilled = false;
entity.assign<AppearsOnRadar>();
if (mpOptions->mPrisonerIsBackground)
{
auto background = SpriteBackground{};

// Keep the grabbing hand in the foreground
background.mRenderSlotMask.reset(1);

entity.assign<SpriteBackground>(background);
}
break;

case ActorID::Passive_prisoner: // Monster in prison cell, passive
entity.assign<BehaviorController>(behaviors::PassivePrisoner{});
entity.assign<BoundingBox>(boundingBox);
entity.assign<ActivationSettings>(ActivationSettings::Policy::Always);
entity.assign<AppearsOnRadar>();
if (mpOptions->mPrisonerIsBackground)
entity.assign<SpriteBackground>();
break;

case ActorID::Rigelatin_soldier: // Rigelatin soldier
Expand Down Expand Up @@ -1917,6 +1928,7 @@ void EntityFactory::configureEntity(
case ActorID::Water_on_floor_1: // Shallow water (variant 1)
case ActorID::Water_on_floor_2: // Shallow water (variant 2)
entity.assign<AnimationLoop>(1);
entity.assign<SpriteBackground>();
break;

case ActorID::Messenger_drone_1: // "Your brain is ours!"
Expand Down Expand Up @@ -1961,6 +1973,7 @@ void EntityFactory::configureEntity(
case ActorID::Flame_jet_3: // Small rocket exhaust flame left
case ActorID::Flame_jet_4: // Small rocket exhaust flame right
entity.assign<AnimationLoop>(2);
entity.assign<SpriteBackground>();
break;

case ActorID::Exit_trigger:
Expand Down
58 changes: 48 additions & 10 deletions src/game_logic/game_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,27 @@ base::Size clampedSectionSize(
std::min(sectionSize.height, map.height() - sectionStart.y)};
}


base::ScopeGuard
applyBrightnessOption(renderer::Renderer* pRenderer, float brightness)
{
if (brightness < 1.0f)
{
auto guard = renderer::saveState(pRenderer);
pRenderer->setColorModulation(base::Color{
base::roundTo<uint8_t>(255.0f * brightness),
base::roundTo<uint8_t>(255.0f * brightness),
base::roundTo<uint8_t>(255.0f * brightness),
255});
return guard;
}
else
{
return base::ScopeGuard{[]() {
}};
}
}

} // namespace


Expand Down Expand Up @@ -990,6 +1011,8 @@ void GameWorld::drawMapAndSprites(
}
else
{
const auto saved =
applyBrightnessOption(mpRenderer, mpOptions->mDropTileBrightness);
state.mMapRenderer.renderBackdrop(
params.mInterpolatedCameraPosition, params.mViewportSize);
}
Expand All @@ -1008,19 +1031,34 @@ void GameWorld::drawMapAndSprites(
};

auto renderBackgroundLayers = [&]() {
state.mMapRenderer.renderBackground(
params.mRenderStartPosition, params.mViewportSize);
state.mDynamicGeometrySystem.renderDynamicBackgroundSections(
params.mRenderStartPosition, params.mViewportSize, interpolationFactor);
state.mSpriteRenderingSystem.renderRegularSprites(mSpecialEffects);
{
const auto saved =
applyBrightnessOption(mpRenderer, mpOptions->mBackTileBrightness);
state.mMapRenderer.renderBackground(
params.mRenderStartPosition, params.mViewportSize);
state.mDynamicGeometrySystem.renderDynamicBackgroundSections(
params.mRenderStartPosition, params.mViewportSize, interpolationFactor);
}

state.mSpriteRenderingSystem.renderBackgroundSprites(
mSpecialEffects, mpOptions->mBackSpriteBrightness);
state.mSpriteRenderingSystem.renderRegularSprites(
mSpecialEffects, mpOptions->mRegSpriteBrightness);
};

auto renderForegroundLayers = [&]() {
state.mMapRenderer.renderForeground(
params.mRenderStartPosition, params.mViewportSize);
state.mDynamicGeometrySystem.renderDynamicForegroundSections(
params.mRenderStartPosition, params.mViewportSize, interpolationFactor);
state.mSpriteRenderingSystem.renderForegroundSprites(mSpecialEffects);
{
const auto saved =
applyBrightnessOption(mpRenderer, mpOptions->mForeTileBrightness);

state.mMapRenderer.renderForeground(
params.mRenderStartPosition, params.mViewportSize);
state.mDynamicGeometrySystem.renderDynamicForegroundSections(
params.mRenderStartPosition, params.mViewportSize, interpolationFactor);
}

state.mSpriteRenderingSystem.renderForegroundSprites(
mSpecialEffects, mpOptions->mForeSpriteBrightness);
renderTileDebris();
};

Expand Down
1 change: 1 addition & 0 deletions src/game_logic/world_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ void copyAllComponents(entityx::Entity from, entityx::Entity to)
copyComponentIfPresent<Shootable>(from, to);
copyComponentIfPresent<SolidBody>(from, to);
copyComponentIfPresent<Sprite>(from, to);
copyComponentIfPresent<SpriteBackground>(from, to);
copyComponentIfPresent<SpriteCascadeSpawner>(from, to);
copyComponentIfPresent<SpriteStrip>(from, to);
copyComponentIfPresent<TileDebris>(from, to);
Expand Down
Loading