Skip to content

Commit

Permalink
Small refactor of transparency handling
Browse files Browse the repository at this point in the history
  • Loading branch information
Yankes committed Mar 23, 2023
1 parent 35971be commit a9d8e11
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 33 deletions.
64 changes: 34 additions & 30 deletions src/Mod/Mod.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2401,19 +2401,36 @@ void Mod::loadResourceConfigFile(const FileMap::FileRecord &filerec)
const YAML::Node& c = (*i)["colors"];
if (c.IsSequence())
{
for (YAML::const_iterator j = c.begin(); j != c.end(); ++j)
for (YAML::const_iterator j = c.begin(); j != c.end(); ++j, ++curr)
{
if (curr == limit)
{
throw Exception("transparencyLUTs mod limit reach");
}

SDL_Color color;
color.r = (*j)[0].as<int>(0);
color.g = (*j)[1].as<int>(0);
color.b = (*j)[2].as<int>(0);
color.r = (*j)[0].as<int>();
color.g = (*j)[1].as<int>();
color.b = (*j)[2].as<int>();
color.unused = (*j)[3].as<int>(2);
// technically it's a breaking change as it always overwrites from offset `start + 0` but no two mods could work correctly before this change.
_transparencies[start + curr++] = color;


for (int opacity = 0; opacity < TransparenciesOpacityLevels; ++opacity)
{
// pseudo interpolation of palette color with tint
// for small values `op` its should behave same as original TFTD
// but for bigger values it make result closer to tint color
const int op = Clamp((opacity+1) * color.unused, 0, 64);
const float co = 1.0f - Sqr(op / 64.0f); // 1.0 -> 0.0
const float to = op * 1.0f; // 0.0 -> 64.0

SDL_Color taint;
taint.r = color.r * to;
taint.g = color.g * to;
taint.b = color.b * to;
taint.unused = 255 * co;
_transparencies[start + curr][opacity] = taint;
};
}
}
else
Expand Down Expand Up @@ -4849,11 +4866,6 @@ const std::map<std::string, SoundDefinition *> *Mod::getSoundDefinitions() const
return &_soundDefs;
}

const std::vector<SDL_Color> *Mod::getTransparencies() const
{
return &_transparencies;
}

const std::vector<MapScript*> *Mod::getMapScript(const std::string& id) const
{
auto i = _mapScripts.find(id);
Expand Down Expand Up @@ -6079,39 +6091,31 @@ Music* Mod::loadMusic(MusicFormat fmt, RuleMusic* rule, CatFile* adlibcat, CatFi
*/
void Mod::createTransparencyLUT(Palette *pal)
{
const int opacityMax = 4;
const SDL_Color* palColors = pal->getColors(0);
std::vector<Uint8> lookUpTable;
// start with the color sets
lookUpTable.reserve(_transparencies.size() * 256 * opacityMax);
for (const auto& tint : _transparencies)
lookUpTable.reserve(_transparencies.size() * TransparenciesPaletteColors * TransparenciesOpacityLevels);
for (const auto& tintLevels : _transparencies)
{
// then the opacity levels, using the alpha channel as the step
for (int opacity = 1; opacity <= opacityMax; ++opacity)
for (const SDL_Color& tint : tintLevels)
{
// pseudo interpolation of palette color with tint
// for small values `op` its should behave same as original TFTD
// but for bigger values it make result closer to tint color
const int op = Clamp(opacity * tint.unused, 0, 64);
const float co = 1.0f - Sqr(op / 64.0f); // 1.0 -> 0.0
const float to = op * 1.0f; // 0.0 -> 64.0

// then the palette itself
for (int currentColor = 0; currentColor < 256; ++currentColor)
for (int currentColor = 0; currentColor < TransparenciesPaletteColors; ++currentColor)
{
SDL_Color desiredColor;

desiredColor.r = std::min(255, (int)Round((palColors[currentColor].r * co) + (tint.r * to)));
desiredColor.g = std::min(255, (int)Round((palColors[currentColor].g * co) + (tint.g * to)));
desiredColor.b = std::min(255, (int)Round((palColors[currentColor].b * co) + (tint.b * to)));
desiredColor.r = std::min(255, (palColors[currentColor].r * tint.unused / 255) + tint.r);
desiredColor.g = std::min(255, (palColors[currentColor].g * tint.unused / 255) + tint.g);
desiredColor.b = std::min(255, (palColors[currentColor].b * tint.unused / 255) + tint.b);

Uint8 closest = currentColor;
int lowestDifference = INT_MAX;
// if opacity is zero then we stay with current color, transparet color will stay same too
if (op != 0 && currentColor != 0)
// if opacity is zero then we stay with current color, transparent color will stay same too
if (tint.unused != 0 && currentColor != 0)
{
// now compare each color in the palette to find the closest match to our desired one
for (int comparator = 1; comparator < 256; ++comparator)
for (int comparator = 1; comparator < TransparenciesPaletteColors; ++comparator)
{
int currentDifference = Sqr(desiredColor.r - palColors[comparator].r) +
Sqr(desiredColor.g - palColors[comparator].g) +
Expand All @@ -6128,7 +6132,7 @@ void Mod::createTransparencyLUT(Palette *pal)
}
}
}
_transparencyLUTs.push_back(lookUpTable);
_transparencyLUTs.push_back(std::move(lookUpTable));
}

StatAdjustment *Mod::getStatAdjustment(int difficulty)
Expand Down
11 changes: 8 additions & 3 deletions src/Mod/Mod.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <vector>
#include <string>
#include <bitset>
#include <array>
#include <SDL.h>
#include <yaml-cpp/yaml.h>
#include "../Engine/Options.h"
Expand Down Expand Up @@ -142,6 +143,12 @@ struct LoadRuleException : Exception
*/
class Mod
{
public:
/// Number of color per opacity level.
constexpr static int TransparenciesPaletteColors = 256;
/// Number of opacity levels.
constexpr static int TransparenciesOpacityLevels = 4;

private:
Music *_muteMusic;
Sound *_muteSound;
Expand Down Expand Up @@ -293,7 +300,7 @@ class Mod
std::vector<std::string> _skillsIndex, _soldiersIndex, _soldierTransformationIndex, _soldierBonusIndex;
std::vector<std::string> _alienMissionsIndex, _terrainIndex, _customPalettesIndex, _arcScriptIndex, _eventScriptIndex, _eventIndex, _missionScriptIndex;
std::vector<std::vector<int> > _alienItemLevels;
std::vector<SDL_Color> _transparencies;
std::vector<std::array<SDL_Color, TransparenciesOpacityLevels>> _transparencies;
int _facilityListOrder, _craftListOrder, _itemCategoryListOrder, _itemListOrder, _researchListOrder, _manufactureListOrder;
int _soldierBonusListOrder, _transformationListOrder, _ufopaediaListOrder, _invListOrder, _soldierListOrder;
std::vector<ModData> _modData;
Expand Down Expand Up @@ -1039,8 +1046,6 @@ class Mod
RuleConverter *getConverter() const;
/// Gets the list of selective files for insertion into our cat files.
const std::map<std::string, SoundDefinition *> *getSoundDefinitions() const;
/// Gets the list of transparency colors,
const std::vector<SDL_Color> *getTransparencies() const;
const std::vector<MapScript*> *getMapScript(const std::string& id) const;
const std::map<std::string, std::vector<MapScript*> > &getMapScriptsRaw() const { return _mapScripts; }
/// Gets a video for intro/outro etc.
Expand Down

0 comments on commit a9d8e11

Please sign in to comment.