1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
|
#include "TableDefinition.h"
#include "parser/DefTokeniser.h"
#include <cmath>
namespace shaders
{
TableDefinition::TableDefinition(const std::string& name) :
DeclarationBase<ITableDefinition>(decl::Type::Table, name),
_snap(false),
_clamp(false)
{}
float TableDefinition::getValue(float index)
{
ensureParsed();
// Don't bother if we don't have any values to look up
if (_values.empty())
{
return 0.0f;
}
auto numValues = _values.size();
if (numValues == 1)
{
return _values[0];
}
if (_clamp)
{
if (index > 1.0f)
{
return _values[numValues - 1];
}
else if (index < 0.0f)
{
return _values[0];
}
// Map the index to the [0..N-1] interval
index *= numValues - 1;
}
else
{
// Only take the fractional part of the index
index = std::fmod(index, 1.0f);
// Mirror negative indices to the positive range (catch negative -0.0f)
if (index < 0 && index != 0.0f)
{
index += 1.0f;
}
// Map the index to the [0..N) interval
index *= numValues;
}
auto leftIdx = static_cast<std::size_t>(std::floor(index)) % numValues;
if (_snap)
{
// If snap is active, just use the left-bound index
return _values[leftIdx];
}
// No snapping, pick the next value to the right to interpolate
auto rightIdx = (leftIdx + 1) % numValues;
float fraction = index - leftIdx;
return (1-fraction)*_values[leftIdx] + fraction*_values[rightIdx];
}
void TableDefinition::onBeginParsing()
{
_snap = false;
_clamp = false;
_values.clear();
}
void TableDefinition::parseFromTokens(parser::DefTokeniser& tokeniser)
{
std::size_t level = 0;
while (tokeniser.hasMoreTokens())
{
std::string token = tokeniser.nextToken();
if (token == "{")
{
if (++level > 1)
{
throw parser::ParseException("Too many opening braces.");
}
}
else if (token == "}")
{
if (level == 0)
{
throw parser::ParseException("Too many closing braces.");
}
--level;
}
else if (token == "clamp")
{
if (level != 0)
{
throw parser::ParseException("The 'clamp' keyword cannot be used at this scope/position.");
}
_clamp = true;
}
else if (token == "snap")
{
if (level != 0)
{
throw parser::ParseException("The 'snap' keyword cannot be used at this scope/position.");
}
_snap = true;
}
else
{
// Expect a numeric value at this point
try
{
_values.push_back(std::stof(token));
}
catch (std::invalid_argument& ex)
{
throw parser::ParseException("Invalid token '" + token + "' encountered: " + ex.what());
}
}
}
}
} // namespace
|